# Errors

The RFC 9457 problem shape, which errors to retry, the order checks run in, and every error code the API returns.

Every error is `application/problem+json` ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)) with three extra members: `code`, `request_id` and, when one field is to blame, `param`.

```json
{
  "type": "https://api.moan.hot/docs/errors#input_rejected",
  "title": "Input rejected",
  "status": 422,
  "detail": "The input could not be processed. You were not charged.",
  "code": "input_rejected",
  "param": "inputs.image",
  "request_id": "req_2b7xk1v0p9q3s4"
}
```

| Member | Meaning |
|---|---|
| `code` | The stable machine-readable code. **Branch on this.** Each code maps to exactly one HTTP status |
| `type` | A link to this code's entry on this page |
| `title` | Fixed text per code |
| `status` | The HTTP status, repeated |
| `detail` | Human-readable text that may change. Show it in logs; never parse it |
| `param` | The request field at fault, such as `variant.duration` |
| `errors[]` | For `invalid_input`: one `{param, message}` per bad field |
| `request_id` | Also in the `X-Request-Id` header. Quote it when you contact support |

## When to retry

Retry only codes marked **Retryable** below: `rate_limited`, `queue_full`, `idempotency_in_progress`, `upstream_unavailable` and `internal_error`.

- Back off exponentially: 1 s, 2 s, 4 s and so on, capped at 60 s, with random jitter.
- When a `Retry-After` header is present, wait at least that long.
- On `POST /generations`, **always retry with the same `Idempotency-Key`** and body, so a retry can never create a second generation.

Everything else needs a change to the request, the key or the account before it can succeed.

## Order of checks on POST /generations

When several problems apply at once, the first one in this order wins:

1. The key: `invalid_api_key`, then `api_key_revoked`, then `api_key_expired`, then `api_key_disabled`, then `insufficient_scope`
2. The account: `account_suspended`, or `account_pending_review` for live keys
3. `rate_limited`
4. `idempotency_key_required`, then the idempotency lookup (`idempotency_in_progress`, `idempotency_key_mismatch`, or a replay)
5. The body: `invalid_request`, then `invalid_input`, then `webhook_url_rejected`
6. The catalogue: `effect_not_found`, then `effect_disabled`, then `variant_unavailable`
7. The inputs: `file_not_found` and `image_*`, then `input_rejected` (or `upstream_unavailable` if checks cannot run)
8. `queue_full`
9. `insufficient_balance`
10. `202 Accepted`

## Generation failures are not HTTP errors

A generation that fails after `202` ends with `status: "failed"` and an `error.code` of `input_rejected`, `gpu_failure`, `timeout`, `upstream_unavailable`, `internal_error` or `effect_retired`. Its hold is released and you are not charged. See [Generations](/docs/generations/).

## Every code

Any route can also answer `route_not_found` (unknown path or method) and `invalid_request` (malformed body).

<ErrorCatalogue />
