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. Try again later.",
    "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. ..."}}

The errors about your account plan name the code code. A request that would take the account past a limit of its plan answers 402 with entitlement_exceeded. entitlement names the limit, limit is its value and used is what the account has. upgrade.plan is the smallest plan that allows one more, and upgrade.addon the add-on that raises the limit; either is null when there is none (When you reach a limit):

JSON
{
  "detail": {
    "code": "entitlement_exceeded",
    "entitlement": "websites_max",
    "limit": 3,
    "used": 3,
    "upgrade": {"plan": "plan-pro", "addon": "addon-websites-pack"},
    "message": "Your Free plan includes 3 websites, and this account has 3. To add more, upgrade to Pro or buy an add-on."
  }
}

On a free server that a brand sells, a feature the free plan leaves out answers 403 with the feature and upgrade_required. coritan.com sells no free server, so a server you order here never answers this (How free servers work):

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, or the request would take the account past a limit of its plan (entitlement_exceeded). For a payment, read detail, then pay with another method. For a limit, remove something first, or raise the limit with the plan or add-on in detail.upgrade.
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"}

A 503 while the service is busy, or while too many requests to the same route are still being answered (Rate limits), answers with the body below and also asks you to wait two seconds with Retry-After: 2. Repeat the request after that wait. A request that changes something may have run before the failure, so read the record again before you repeat it, or use an idempotency key on the routes that take one:

JSON
{"detail": "The service is busy. Try again in a moment."}

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

Code Status Meaning
entitlement_exceeded 402 The request would take the account past a limit of its plan, such as its websites, load balancers or team members. detail.upgrade names what raises the limit.
plans_not_open 403 Account plans are not open on your account yet, so you cannot order, change or try one (Plans open in stages).
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.