Platform
Learn
Developer docs User guide Quickstart Blog
Company
Services About Contact Links Get started

API errors and status codes

Updated

Raytha reports API failures with a status code and a JSON body. The body takes one of three shapes depending on where the failure happened. This page lists the status codes, shows each shape, and gives a small client function that turns any of them into a readable message.

Status codes

StatusMeaningRetry?
200, 201, 202Success. 201 is a create. 202 is a batch that runs in the background.-
400The request is invalid: a field failed validation, the filter is wrong, the body could not be read, or a rule was broken.No. Fix the request.
401The API key is missing or wrong, or its admin lacks the permission.No.
404The item, content type, template or route does not exist.No.
422An id is not in the 22-character id format.No.
500An unexpected failure on the server.Yes, with backoff. Then check the server log.

A proxy or host in front of Raytha can add its own 502, 503 and 504. Treat those as retryable too.

The three error shapes

1. Problem details

Most failures, including every 401, 404, 422, 500 and bad filter, use the application/problem+json shape. detail is the message to show. The extra error field repeats it for older clients.

{
  "type": "https://httpstatuses.io/404",
  "title": "Not found",
  "status": 404,
  "detail": "Entity \"Content item\" (h5anxM6u4UW80v09zzQjXg) was not found.",
  "instance": "/raytha/api/v1/ContentItems/posts/h5anxM6u4UW80v09zzQjXg",
  "success": false,
  "error": "Entity \"Content item\" (h5anxM6u4UW80v09zzQjXg) was not found."
}

Some lookups return the generic The resource you requested was not found. instead of naming the entity.

TitleStatusDetail you will see
Unauthorized401Invalid API key. (missing, unknown or revoked key) or Unauthorized access. (valid key, missing permission)
Not found404The missing entity, or the generic message
Invalid identifier422Invalid format of identifier.
Invalid filter400What is wrong with the filter. See Filtering.
Request failed400The message of the rule that was broken
Bad request400The request body could not be read.
Server error500An unknown error has occurred.

2. Validation problem details

When Raytha validates a request body and finds field-level problems, or cannot bind the JSON to the request type, it adds an errors map. Keys are field names, and values are lists of messages. A property that has the wrong type appears under a $. path:

{
  "title": "One or more validation errors occurred.",
  "status": 400,
  "detail": "saveAsDraft: The JSON value could not be converted to System.Boolean.",
  "errors": {
    "$.saveAsDraft": ["saveAsDraft: The JSON value could not be converted to System.Boolean."]
  }
}

3. Command failure

Content item commands such as create and edit report validation failures as a plain envelope, with 400 and all messages joined by a semicolon:

{
  "result": null,
  "error": "'Title' field is required.;category is not a recognized field for content type: Post",
  "success": false
}

Do not parse that string by splitting on ; if you can avoid it. Show it as one message.

Handle them in a client

This function reads all three shapes, and separates errors you should fix from errors you can retry.

function describeError(status, body) {
  if (!body) return `HTTP ${status}`;
  if (body.errors) {
    // Field-level problems: { "errors": { "title": ["'Title' field is required."] } }
    const fields = Object.entries(body.errors).map(
      ([field, messages]) => `${field}: ${[].concat(messages).join(" ")}`
    );
    if (fields.length > 0) return fields.join("; ");
  }
  // Problem details have `detail`. Command failures have `error`, with messages joined by ";".
  return body.detail || body.error || body.title || `HTTP ${status}`;
}

async function call(url, options) {
  const response = await fetch(url, options);
  const body = await response.json().catch(() => null);
  if (response.ok) return body;

  const message = describeError(response.status, body);
  if (response.status >= 500) {
    throw new Error(`Raytha failed (${response.status}): ${message}. Retry later.`);
  }
  throw new Error(`Request rejected (${response.status}): ${message}. Fix the request.`);
}

With curl, print the status code and fail on errors:

status=$(curl -s -o response.json -w '%{http_code}' \
  "$RAYTHA_URL/raytha/api/v1/ContentItems/posts/not-a-real-id" \
  -H "X-API-KEY: $RAYTHA_API_KEY")

if [ "$status" -ge 400 ]; then
  echo "HTTP $status: $(jq -r '.detail // .error // .title' response.json)" >&2
  exit 1
fi

Common causes

You seeCheck
401 Invalid API key.The X-API-KEY header is present, the key was copied in full, and its admin is active.
401 Unauthorized access.The admin's role includes the permission from Authentication for this content type or resource.
404 on a content type URLYou used the content type's developer name, not its label.
422 Invalid format of identifier.The id is a 22-character id from Raytha, not a number, a GUID or a route path.
400 … is not a recognized fieldThe key in content is not a field developer name of that content type.
400 … 'X' field is required.Publishing needs every required field. Save as a draft, or send the field.
400 Invalid filterQuote string values and use eq. See Filtering.
500Look at the Raytha server log for the time of the request. The response never includes a stack trace outside Development.

Gotchas

  • A missing permission is a 401, not a 403. Read detail to tell a bad key from a missing permission.
  • The API never redirects to an HTML error page. Every path under /raytha/api answers in JSON. If you get HTML, you are not reaching Raytha, or your URL is missing /raytha/api.
  • Validation messages come in different shapes. Check for errors, then detail, then error.
  • A batch reports failures per item. The 202 response means the job was queued, not that every item was created. Read statusInfo on the task.
  • A failed write may still be partly applied in a batch. Items are created independently. Re-send only the failed ones.

Next steps