Errors
One envelope, stable machine codes, and what is safe to retry.
Envelope
Native and management routes return:
{
"error": {
"type": "invalid_request",
"code": "schema_invalid",
"message": "messages[1].content[0].tool_use_id: unknown tool call",
"param": "messages[1].content[0].tool_use_id",
"request_id": "01K4N4V8Z8W3Q0G8S4YV6D5V2M"
}
}The compat routes mirror the vendor's envelope so SDK error classes keep working: OpenAI's {"error":{"message","type","param","code"}} and Anthropic's {"type":"error","error":{"type","message","code"}}. In both, code is the aiml code below, and the x-aiml-request-id header is always present.
Types and status codes
| HTTP | type | Codes |
|---|---|---|
| 400 | invalid_request | schema_invalid (with param), context_length_exceeded, unknown_model, body_too_large, image_url_unreachable (an image URL the gateway had to fetch for the provider could not be retrieved: https only, public hosts only, 20 MiB, 5 s) |
| 401 | authentication | key_invalid, key_revoked, key_expired |
| 402 | insufficient_credits | insufficient_credits (header x-aiml-required-micro), budget_exceeded.daily, budget_exceeded.monthly (param says whose ceiling: budget_* the key's, project_budget_* the project's) |
| 403 | permission | scope_missing, model_not_allowed, ip_not_allowed, data_policy_violation |
| 404 | not_found | not_found |
| 409 | conflict | idempotency_in_progress, idempotency_key_reuse |
| 422 | unsupported_feature | unsupported_feature.<name> (for example unsupported_feature.tools, unsupported_feature.n) |
| 429 | rate_limited | rpm, tpm, concurrency, upstream_capacity (header Retry-After) |
| 502 | upstream | upstream_error, upstream_eof, upstream_invalid_response |
| 503 | upstream | no_capacity, upstream_capacity, draining, paused, analytics_unavailable, store_unavailable |
| 504 | upstream | upstream_timeout |
| 500 | internal | internal |
A 503 is always retryable and never the request's fault: draining and paused are the platform stepping back for a moment, analytics_unavailable is a usage or request-history route whose analytics store is unreachable (money routes never depend on it), and store_unavailable is a control-plane route whose database is unreachable. Retry after a few seconds; the inference routes are unaffected by the last two.
What to retry
- Retry with backoff:
429(honourRetry-After),503,504,502 upstream_eof. The gateway has already tried the other endpoints it had for the model; a retry a few seconds later reaches a different capacity picture. - Do not retry unchanged:
400,401,403,422. Fix the request, the key or the scope. - Top up, then retry:
402. - Duplicates. A retried call is a new request with a new id and a new charge; retry only on the statuses above, and keep
max_tokenssmall on calls you expect to repeat.
Streams that end early
A stream that has started cannot change its status code. The gateway instead ends the SSE stream with an error frame in the dialect's shape (data: {"error": …} on OpenAI, event: error on Anthropic), settles what was delivered, and records the reason as the stop reason of the request (x-aiml-stop on the response, stop on the generation record): budget_exceeded (credits exhausted mid-stream), timeout (idle upstream or max_duration_ms reached), error with code draining_timeout (the pod shut down before the stream finished; retry immediately), cancelled (the client went away).
Warnings
Non-fatal problems never fail a request. They are listed in the x-aiml-warnings header (comma-separated codes) and in aiml.warnings in the JSON body with a message and a param: param_dropped, param_clamped, stop_truncated, feature_degraded, provider_block_dropped, schema_rewritten, system_folded, tool_result_media_moved, usage_estimated, pause_turn.