# Errors

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

Source: https://docs.coritan.com/api/errors/

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.

## The error body

### A sentence

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.

### An object with a code

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 list of field 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 codes

| 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](/api/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](/api/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](/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"}
```

## Error codes

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](/api/authentication/#authentication-errors) lists the codes about credentials, and [Idempotent requests](/api/idempotency/) the codes about repeated requests.

## 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.
