# Errors

> The error envelope and the codes your client can branch on.

Every error is an envelope with `status: "error"`. Branch on `data.code`, never on `title` or `detail`: the text can change, the codes cannot.

```json
{
  "status": "error",
  "data": {
    "id": "0fc9bd0773e54d9c66bdfbf38c4df7ae",
    "status": 409,
    "code": "idempotency_conflict",
    "title": "Conflict",
    "detail": "Idempotency key already used by parsing 0199d8e4c2a07f4b8d1e5a6b7c8d9e0f"
  }
}
```

| Field    | Description                                                            |
| :------- | :--------------------------------------------------------------------- |
| `id`     | The request id: quote it when you contact support.                     |
| `status` | The HTTP status.                                                       |
| `code`   | A domain code from the list below, or `H_<status>` when there is none. |
| `title`  | A short human-readable summary.                                        |
| `detail` | A human-readable explanation, for logs and people.                     |

***

## 🧭 Domain codes

| Status | Code                    | When                                                                                                            |
| :----- | :---------------------- | :-------------------------------------------------------------------------------------------------------------- |
| `400`  | `unreadable_file`       | The file type is detected, but the file is corrupt and its pages cannot be read.                                |
| `400`  | `unsupported_format`    | The file type cannot be detected, does not match the file extension, or cannot be read with `accurate` Parsing. |
| `402`  | `balance_exhausted`     | The workspace has no Credits left. See [Credits](https://docs.axelered.com/jobs_guide#-credits).                                         |
| `403`  | `perimeter_not_allowed` | The workspace's [Compliance Guard](https://docs.axelered.com/config_guide#-compliance-guard) forbids the `external` Perimeter.           |
| `409`  | `idempotency_conflict`  | The `idempotency_key` was already used in the workspace. See below.                                             |
| `413`  | `file_too_large`        | The file is over 10 MB.                                                                                         |
| `413`  | `too_many_pages`        | The Job would read more than 100 pages with `accurate` Parsing. See [Documents](https://docs.axelered.com/documents_guide).              |
| `422`  | `invalid_output_schema` | The `outputSchema` of an [Extraction](https://docs.axelered.com/extract) is not a valid JSON Schema.                                     |
| `425`  | `output_not_ready`      | The Parsing has not finished yet: read it again later.                                                          |
| `503`  | `perimeter_unavailable` | The Perimeter cannot run this Job. See [Perimeters](https://docs.axelered.com/config_guide#-availability).                               |

New codes may be added: treat an unknown code like its HTTP status.

On `idempotency_conflict`, the `Location` header is the path of the Document or Job that already holds the key, e.g. `/parsings/{parsing_id}`: read it to get its status.

***

## 🔢 Other errors

Errors without a domain code carry `H_<status>`, e.g. `H_404` for a missing resource or `H_422` for an invalid request. For those, branch on the HTTP status.

***

## ⏱️ Rate limits

Each workspace can make 10 requests per second, with bursts of up to 10. All its API Keys and the GUI share this limit; a global API Key has its own.

Over the limit you get `429` with code `H_429` and a `Retry-After` header: the whole seconds to wait before the next request. A `429` may also come from the network edge, without `Retry-After` or this envelope: then back off exponentially (1 s, 2 s, 4 s...).
