> This is the Markdown of https://backed.giving/developers/guides/errors, a page of the Backed developer documentation. Every page is listed at https://backed.giving/developers/llms.txt.

# Errors

What every error code means, the status it comes with, and which ones are safe to retry.

A refused request answers a 4xx or 5xx status with a small JSON body. `error` is a machine code your system switches on; `error_description`, where present, is a fixed English sentence for the person reading a log.

A refusal:

```json
{
  "error": "invalid_request",
  "error_description": "limit is invalid"
}
```

- `invalid_transition` also carries `current_status`, the state the record is in.
- `validation_failed` also carries `fields`, the name of each field the product’s own form would refuse.
- A write refused for any reason has changed nothing.

## Every code

Error codes:

| Status | Code | When |
| --- | --- | --- |
| 400 | `idempotency_key_required` | The write has no Idempotency-Key header of 1 to 255 characters. |
| 400 | `invalid_request` | A query parameter is invalid, or a write’s body is not a JSON object. |
| 400 | `unsupported_grant_type` | The grant type is not client\_credentials. |
| 401 | `invalid_client` | Client authentication failed: an unknown client\_id, a wrong secret, a revoked credential or another Organisation’s, or API access is not Full. |
| 401 | `invalid_token` | The token is missing, invalid, expired or revoked, of another Organisation, or API access is not Full. Ask for a new token. |
| 403 | `approval_limit_exceeded` | The amount is above the run-as Administrator’s approval limit. |
| 403 | `forbidden` | The run-as Administrator lacks the permission, or the record is outside their Data Access Rules. |
| 403 | `https_required` | The request was sent over plain HTTP and was not processed. |
| 403 | `insufficient_scope` | The credential does not hold the scope the route needs. |
| 403 | `run_as_disabled` | The credential has no run-as Administrator, or that person is no longer one. |
| 404 | `module_disabled` | The Organisation has the module this route belongs to turned off. |
| 404 | `not_found` | An unknown host or path, or an id that is unknown, deleted or of another Organisation. |
| 405 | `method_not_allowed` | The method is not served on this path. `Allow` lists what is: `GET, HEAD` on a read path, `POST` on /oauth/token, the write’s own method on a write path. |
| 409 | `conflict_declared` | The Assessor has declared a conflict of interest with an application. |
| 409 | `file_not_scanned` | The file has not finished its malware scan; try the attach again shortly. |
| 409 | `idempotency_in_progress` | The first request with this Idempotency-Key has not finished. Nothing was written; retry after the given seconds. |
| 409 | `invalid_state` | The record is not in a state that admits this write. |
| 409 | `invalid_transition` | The move is not open from where the record stands; `current_status` says where that is. |
| 412 | `precondition_failed` | If-Match is missing, malformed or not the record’s current lock\_version, or the record changed under the write. Nothing was written. |
| 413 | `payload_too_large` | The body, or the declared file, is larger than the limit that applies. |
| 415 | `unsupported_media_type` | The body is not application/json, or the target does not accept the file’s content type. |
| 422 | `file_infected` | The file failed its malware scan and was not attached. |
| 422 | `idempotency_key_reused` | The Idempotency-Key was used in the last 24 hours for a different method, path or body. |
| 422 | `unknown_field` | The body has a property the route does not document; the first is named. |
| 422 | `unknown_tag` | A tag is not one of the Organisation’s tags. None is created. |
| 422 | `validation_failed` | Body values the product’s own form would refuse; `fields` names each. |
| 429 | `rate_limited` | A rate limit was exceeded: 120 requests a minute per credential, 30 token requests a minute per client\_id. |
| 500 | `server_error` | An unexpected server error. |
| 503 | `temporarily_unavailable` | The Organisation’s API access cannot be determined, or a dependency is unavailable. Retry after the given seconds. |

## Which to retry

- `429 rate_limited`, `503 temporarily_unavailable` and `409 idempotency_in_progress` carry `Retry-After`: wait that many seconds and send the same request again, with the same `Idempotency-Key` for a write.
- `500 server_error`: retry a read later. Retry a write with the same `Idempotency-Key`, so that a write that did happen is answered again rather than made twice. See the idempotency guide.
- `401 invalid_token`: ask for a new token, then retry.
- Anything else is about the request itself: change it before you send it again.

The OData reporting feed answers its own query errors in the OData error body: `400 bad_request`, `404 not_found`, `410 delta_token_expired`, `501 not_implemented`. See [Power BI](https://backed.giving/developers/guides/power-bi.md) and [Idempotency](https://backed.giving/developers/guides/idempotency.md).
