Errors
Every HTTP status and error type the gateway returns in the Anthropic and OpenAI formats, what causes each and whether to retry, errors during a stream, and the request ids to send to support.
When to use this page
A request failed and you want to know why, whether to retry it, or what to send to support. Limits and backoff are on Rate limits.
Error format
Errors use the format of the API you called, with the same HTTP status on both.
/v1/* (Anthropic format):
{
"type": "error",
"error": {
"type": "not_found_error",
"message": "model: anthropic/no-such-model"
},
"request_id": "0b1c6f2e-5d4a-4f7e-9a51-3f0e8d2c7b19"
}/openai/v1/* (OpenAI format):
{
"error": {
"message": "The model `anthropic/no-such-model` does not exist or you do not have access to it.",
"type": "invalid_request_error",
"param": "model",
"code": "model_not_found"
}
}The Anthropic and OpenAI SDKs turn these into their own error classes (for example NotFoundError), so you rarely parse them yourself. See the error handling sample in curl, Node.js or Python.
Status codes
| Status | Anthropic type | OpenAI type / code | Cause | Retry? |
|---|---|---|---|---|
| 400 | invalid_request_error | invalid_request_error / null | The body isn't valid JSON, a required field is missing or wrong (model, max_tokens, messages), the model refused a parameter, or the OpenAI-compatible API doesn't support a field you sent | No. Fix the request. |
| 401 | authentication_error | invalid_request_error / invalid_api_key | The key is missing, wrong, revoked or expired | No. Check the key. |
| 402 | billing_error | insufficient_quota / insufficient_quota | The organization's balance is zero or below, or the key reached its spend limit | No. Add credit or raise the limit. |
| 403 | permission_error | permission_error / null | The key isn't allowed to use this model, or the organization is suspended | No |
| 404 | not_found_error | invalid_request_error / model_not_found | The model is unknown, retired, or in preview and the key has no preview access | No. Use a model from Models. |
| 413 | request_too_large | invalid_request_error / request_too_large | The request body is over 32 MB | No. Send less. |
| 429 | rate_limit_error | rate_limit_error / rate_limit_exceeded | The key went over its requests per minute, or the providers are rate limiting this model | Yes, after retry-after |
| 500 | api_error | server_error / null | An unexpected error in the gateway or at the provider | Yes, a few times with backoff |
| 504 | timeout_error | server_error / timeout | A non-streaming request took longer than 590 seconds | Send it again with "stream": true |
| 529 | overloaded_error | 503, server_error / overloaded | No capacity for this model right now, or every provider the gateway tried failed | Yes, after retry-after |
The OpenAI-compatible API returns 503 where the Anthropic format returns 529, because OpenAI clients don't know 529. Its 404 for a model also sets "param": "model".
None of these errors is charged. See How billing works.
Messages you may see
| Status | message |
|---|---|
| 400 | Request body is not valid JSON, or <field>: <problem>, such as max_tokens: … or n: only 1 choice per request is supported |
| 401 | Missing API key. Send it in the x-api-key or Authorization: Bearer header. |
| 401 | Invalid API key, This API key has been revoked, This API key has expired |
| 402 | Your credit balance is too low. Add credits in the EZAT Router dashboard. |
| 402 | This API key reached its daily spend limit of … (or monthly, total) |
| 403 | This API key is not allowed to use … |
| 403 | This organization is suspended. Contact support@ezat.io. |
| 404 | model: <the name you sent> |
| 429 | This API key exceeded its requests-per-minute limit (retry-after: 30) |
| 429 | Rate limited upstream. Please retry shortly. (retry-after: 10) |
| 504 | The model took longer than 590 seconds. Send long requests with "stream": true. |
| 529 | Overloaded, or … has no available capacity right now (retry-after: 5) |
A 400 that the model itself returns (for example a parameter the model doesn't accept) carries the model's own message.
Paths that don't exist
A path the gateway doesn't serve, such as /v1/messages/batches or /v1/files, returns 404 in a plain format, not in either envelope:
{ "statusCode": 404, "message": "Cannot POST /v1/messages/batches" }Errors during a stream
Once a streamed response has started, the HTTP status is already 200. If something fails after that, the gateway sends one error event and ends the stream. The request is marked Failed in Usage and isn't charged.
Anthropic format: an error event, with no message_stop after it.
event: error
data: {"type":"error","error":{"type":"api_error","message":"Upstream provider error"}}OpenAI format: a chunk with an error object, then [DONE].
data: {"error":{"message":"Upstream provider error","type":"server_error","param":null,"code":null}}
data: [DONE]The error types are the same as in the table above. The Anthropic and OpenAI SDKs raise an APIError (or a subclass) when they read it, and don't retry it: send the request again yourself if you want to.
If your client disconnects mid-stream, there is no error event; see interrupted streams.
Request ids
Two response headers identify a request:
| Header | On | Value |
|---|---|---|
request-id | Messages and chat completions that passed the gateway's checks and reached a model, successful or not, streamed or not | The id of the request in your Usage |
x-request-id | Every response, including refused requests | An id for this HTTP call. If you send your own x-request-id (letters, digits, ., _, :, -, up to 128 characters), it is used and sent back. |
- In the Anthropic format, the error body's
request_idis thex-request-id. - On the OpenAI-compatible API, a completion's
idischatcmpl-followed by itsrequest-id. - The Anthropic SDKs expose
request-id(message._request_id, anderror.request_idin Python orerror.requestIDin Node). For a refused request there is norequest-id, so readx-request-idfrom the error's response headers. - The OpenAI SDKs expose
x-request-id(completion._request_id,error.request_idin Python,error.requestIDin Node).
Contact support
Email support@ezat.io with:
- The
request-id, if the response had one, and thex-request-id. - The time of the request (with its time zone), the model, and which API you called (
/v1/messagesor/openai/v1/chat/completions). - The HTTP status and the error
message.
Never send your API key. Request and response bodies aren't stored, so include the parts of the request that matter.
For AI agents
- Read the HTTP status first, then
error.type(Anthropic format) orerror.code(OpenAI format). - Don't retry 400, 401, 402, 403, 404 or 413. Fix the request, tell the user to check the key or add credit at https://router.ezat.io/billing, or pick a model from
GET https://api.router.ezat.io/v1/models. - Retry 429, 500, 529 and 503 with exponential backoff, waiting at least the
retry-afterseconds when the header is there. The official Anthropic and OpenAI SDKs already do this, twice by default. - For a 504
timeout_error, resend with"stream": trueinstead of retrying as is. - A stream can end with an
errorevent (Anthropic) or anerrorchunk (OpenAI) after a 200. Treat it like a 500. - When reporting a problem, give the user the
request-idandx-request-idheaders and the time. Never include the API key.