# Error responses

> Parse the common Router error envelope and recover according to status and code.

Router returns errors as JSON before a stream starts.

```json
{
  "error": {
    "message": "No provider is available for this model",
    "type": "server_error",
    "code": "no_priced_provider_available"
  }
}
```

Use the HTTP status for broad control flow, the stable `code` for a specific product message, and `message` for a human-readable explanation.

## Common API errors

| Status | Code or category                                                                      | Recovery                                                                                                                                                                    |
| ------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400    | Invalid body, unknown model, `output_limit`, `prompt_too_large`, or unsupported input | Correct the request before trying again.                                                                                                                                    |
| 400    | `context_length_exceeded`                                                             | The messages exceed the edition’s context window in tokens. Shorten them before trying again.                                                                               |
| 400    | `stream_required`                                                                     | A non-streaming request asked for more than 512 output tokens or sent more than about 24 KB of message text. Set `stream` to `true`, or shorten the request.                |
| 400    | `idempotency_key_required`                                                            | Send a caller-generated UUID in `Idempotency-Key`.                                                                                                                          |
| 401    | `auth_no_token` or `invalid_api_key`                                                  | Supply a valid bearer key or rotate an expired or revoked key.                                                                                                              |
| 402    | `insufficient_credits`                                                                | Add shared credits or lower the request maximum.                                                                                                                            |
| 402    | `budget_exhausted`                                                                    | Router's UTC monthly spending cap is reached.                                                                                                                               |
| 402    | `charge_limit_exceeded`                                                               | This request's worst-case charge exceeds its authorized maximum.                                                                                                            |
| 403    | `account_disabled`                                                                    | Resolve account access; repeated requests will not help.                                                                                                                    |
| 409    | `provider_price_changed`                                                              | Review the current selected offer price and explicitly accept its new revision in a new logical request.                                                                    |
| 409    | `provider_offer_unavailable`                                                          | Select another published eligible offer, or explicitly omit the selection for Auto.                                                                                         |
| 409    | `idempotency_conflict`                                                                | This UUID was already used with a different body, credential, or `X-Max-Charge-Credits` value. Resend the original terms, or use a new UUID for a new request.              |
| 409    | `request_in_progress`                                                                 | Router is still admitting the earlier request with this UUID. Check its credit receipt, then retry with the same UUID and body if needed.                                   |
| 409    | `request_already_exists`                                                              | A streaming request with this UUID already exists. Streams are not replayed; check its credit receipt.                                                                      |
| 429    | Request-rate or concurrency limit                                                     | Respect `Retry-After` and reduce parallel work.                                                                                                                             |
| 503    | `no_priced_provider_available`                                                        | No eligible paid provider can accept this model now.                                                                                                                        |
| 503    | `no_provider_for_length`                                                              | No online provider serves a request this long right now. Shorten the messages or the answer limit; an immediate retry will not help, so respect `Retry-After` (60 seconds). |
| 503    | `selected_provider_unavailable`                                                       | The selected computer is busy or offline; Router does not silently fall back.                                                                                               |
| 503    | `self_provider_only`                                                                  | Select a provider owned by another account.                                                                                                                                 |
| 503    | `request_capacity`                                                                    | Router’s bounded active-request capacity is full; retry later.                                                                                                              |
| 503    | `credit_admission_unavailable` or `settlement_pending`                                | Keep the request UUID and check its credit receipt; never start a new paid request just to recover.                                                                         |
| 503    | `slippage_tolerance_exceeded`                                                         | No charge or reservation. Review `error.minimum_slippage_tolerance` and submit new terms with a new request UUID if appropriate.                                            |
| 503    | `pricing_pending`                                                                     | Pricing research is running; no charge or reservation. Retry unchanged terms after `Retry-After`.                                                                           |
| 503    | `suggested_price_unavailable`                                                         | Baseline storage or generation is unavailable; no charge or reservation. Retry later or choose another model.                                                               |
| 503    | Generation or dependency failure                                                      | Show a temporary failure and retry the same logical request ID only when safe.                                                                                              |

Error messages can evolve. Branch application behavior on status and code rather than matching the English message.

## Streaming errors

After streaming headers are sent, a generation failure arrives as an SSE data event with an `error` object and the request's `request_id`. The HTTP status may already be 200.

```text
data: {"error":{"message":"Generation or settlement interrupted","type":"server_error","code":"provider_timeout"},"request_id":"$REQUEST_ID"}

data: [DONE]
```

An error event is terminal for that generation. A `[DONE]` marker may still follow; it does not turn the reply into a success. Do not treat already-received content as a complete answer, and check the request's credit receipt before retrying. Codes vary by failure.

When streaming, an input longer than the model's context window arrives this way too, as `"type":"invalid_request_error","code":"context_length_exceeded"` with no answer text. Retrying the same messages fails again: shorten them first. No tokens were generated, so the request's reservation is released.

## Retry headers

429 and temporary capacity responses can include `Retry-After`. Interpret an integer value as seconds, add jitter before retrying, and keep the total number of attempts bounded.

> **Keep one ID for one request**
> Retry an uncertain result with the same `Idempotency-Key` UUID and unchanged body. A new UUID starts a separate paid request and can create another charge.

See [retries, timeouts, and cancellation](https://router.optimai.network/docs/retries-and-timeouts.md) for an application strategy.
