njin

Errors

API errors are JSON with a message. Some add details.

{ "message": "Unauthorized" }

Status codes

Status When Example
400 The request cannot be done "You cannot delete your own account"
401 No credential, an invalid one, or a kind of credential this endpoint does not accept "Unauthorized"
403 The credential is valid but not allowed. Also a cookie request that changes data without X-Requested-With, and a second setup "Forbidden", "Setup already completed"
404 The record exists, but the caller's own grant does not cover it. Also a token or connected app that is not yours "Not Found", "Token not found"
409 A conflict with the current state. See below "Field \"slug\" must be unique..."
422 The request is not valid. See below "Validation error"
429 Too many failed logins for an email "Too many failed attempts. Try again in a few minutes."
500 An unexpected error, including an error thrown from a hook "Internal Server Error"

A missing record is not a 404. See Model endpoints.

Validation errors

When a body or a query parameter breaks a rule, the response is 422, and errors lists each problem with the field it belongs to:

{
  "message": "Validation error",
  "errors": [
    { "path": "title", "message": "Too small: expected string to have >=3 characters" },
    { "path": "status", "message": "Invalid option: expected one of \"DRAFT\"|\"PUBLISH\"" }
  ]
}

A missing required field is reported the same way, for example "Invalid input: expected array, received undefined". The same format is used for query parameters, such as a limit above 100:

{
  "message": "Validation error",
  "errors": [{ "path": "limit", "message": "Too big: expected number to be <=100" }]
}

Other 422 responses have their own messages:

Where Message
Creating or updating an access group "Some grants are not valid", with an errors list of strings
Uploading a file "This file type can't be uploaded (HTML, JavaScript and XML run on the site's origin)."
Narrowing a connected app "Access can be narrowed here, not widened"
Updating a localized field of a vars group with a plain value A message asking for an object keyed by locale

Unique conflicts

A 409 with a field means a unique value is already taken. It is returned by POST and PUT:

{ "message": "Field \"slug\" must be unique — value already exists", "field": "slug" }

Other 409 responses:

When Message
Discarding a record that was never published "Post is not published, nothing to discard"
Deleting the last language of a record "..." is the only language left — delete the record instead
A change that would leave nobody with full access A message saying so

Handling errors in a client

const res = await fetch("/api/post", {
  method: "POST",
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
  body: JSON.stringify(body),
});

if (res.status === 422) {
  const { errors } = await res.json();
  for (const { path, message } of errors) showFieldError(path, message);
} else if (res.status === 409) {
  const { field, message } = await res.json();
  showFieldError(field, message);
} else if (!res.ok) {
  const { message } = await res.json();
  throw new Error(message);
}