Skip to content
Coritan Docs

Errors

The status codes and error bodies the Coritan API returns, the fields to read in each, and what to do about them.

View as Markdown

A request that fails answers with a status code of 400 or more and a JSON body. Read the status code first: it says what kind of failure it is. The body's detail field then says what went wrong, in one of the three shapes below.

Most errors carry one sentence, written to be shown to a person:

JSON
{"detail": "Invoice not found"}

Branch on the status code, not on the words.

Errors that a program is expected to act on carry an object. error is a code to branch on, message is the sentence to show, and some codes add fields of their own:

JSON
{
  "detail": {
    "error": "rate_limited",
    "message": "Too many requests for this action. Please wait and try again.",
    "action": "container.power",
    "retry_after_seconds": 60
  }
}

A few errors name the code reason instead of error, such as a locked server:

JSON
{"detail": {"reason": "server_locked", "message": "We have locked this server because activity on it broke our acceptable use policy, and our team is reviewing it. ..."}}

A feature your plan does not include answers 403 with the feature and upgrade_required:

JSON
{
  "detail": {
    "feature": "backups",
    "reason": "free_plan",
    "message": "Backups are not included on the free plan. Upgrade to a paid plan, or download your world from the file manager.",
    "upgrade_required": true
  }
}

Some orders that fail a check of their settings answer 422 with a list of sentences: {"detail": {"errors": ["..."]}}.

A body, query or path value that is missing or has the wrong type answers 422 with one entry for each field. loc says where the field is, and msg what is wrong with it:

JSON
{
  "detail": [
    {
      "type": "missing",
      "loc": ["body", "password"],
      "msg": "Field required",
      "input": {"email": "alex@example.com"}
    }
  ]
}
Status Meaning What to do
400 The request is well formed, but it cannot be carried out as sent. detail says why. Change the request.
401 The credential is missing, expired, or the wrong kind for the route. Refresh the token or sign in again, as Authentication describes.
402 A payment did not complete, such as a card the bank declined. Read detail, then pay with another method.
403 You may not do this: your role or plan does not allow it, the account is suspended, or the record belongs to someone else. A Client API request with no Authorization header also answers 403 Not authenticated. Check the credential and what it may do. Do not retry unchanged.
404 The path or the record does not exist, or it belongs to another account. Check the ID and the path.
409 The request conflicts with the record's state: a name is taken, the same action is already running, or the record is being deleted. Read the record again, then decide.
413 A file or a body is larger than the route accepts. detail gives the limit. Send less.
422 A field is missing or not valid. Fix the fields detail names.
423 The server is locked, and detail.reason is server_locked. The lock does not delete your files. Reply to the support ticket that came with the lock.
429 Too many requests. Wait as long as Retry-After says. Rate limits lists the limits.
500 Something failed on Coritan's side. detail is Internal server error. Retry later. If it keeps failing, contact support with the time and the request.
502 A system the API depends on refused or failed, such as a payment provider or a domain registrar. detail says which. Retry later.
503 The API or one of its services is not available right now. Retry after the Retry-After header, or later when there is none.

A 503 while the API starts up has its own body, and asks you to wait two seconds with Retry-After: 2:

JSON
{"detail": "Service unavailable: database not ready", "status": "not_ready"}

These codes in detail.error or detail.reason come up on many routes. The page for each product lists the ones it adds.

Code Status Meaning
turnstile_failed 403 The verification check is on, and turnstile_token is missing or did not pass.
mfa_required 401 A pending token from a sign-in with two-factor authentication was sent to a route that needs a full sign-in.
reauth_required 403 An Organization API action needs a step-up in the last 10 minutes. max_age_seconds says how long one lasts.
rate_limited 429 An action's own budget is spent. action names it, and retry_after_seconds gives the length of its window.
free_limit_reached 409 You already have the most of that free plan an account may hold. Remove one, or choose a paid plan.
free_tier_paused 503 Free servers are at capacity, so a storefront takes no orders for them right now.
plan_not_sold_here 403 The plan cannot be ordered through this API.
server_locked 423 The server is locked while Coritan reviews it.
server_deleting 409 The server is being deleted, so it takes no more actions.

The Commerce API and the Store API answer every error with an object like this, with codes such as not_found, invalid, conflict, forbidden, commerce_not_enabled, scope_required and idempotency_key_reused. Authentication lists the codes about credentials, and Idempotent requests the codes about repeated requests.

Errors from in front of the API

Section titled Errors from in front of the API

The proxy in front of the API can refuse a request before the API sees it. Its answers carry error at the top level and no detail:

Status Body Meaning
429 {"error":"Too many requests"} Your address sent too many requests or opened too many connections. Retry-After is 1.
413 {"error":"Request body too large"} The body is larger than the proxy accepts.

Handle both bodies: read detail when it is there, and error when it is not.