Bu sayfa yalnızca İngilizce.

Errors

The shape follows your endpoint

An error body is returned in the dialect your SDK parses, decided by the path you POSTed to, never by which sharer or model the request happened to reach.

/v1/chat/completions, /v1/responses and every other OpenAI-style endpoint (embeddings, images, moderations, OCR, video, audio, music, decisions):

JSONjson
1{
2 "error": {
3 "message": "…",
4 "type": "invalid_request_error",
5 "code": "context_length_exceeded"
6 }
7}

/v1/messages:

JSONjson
1{
2 "type": "error",
3 "error": { "type": "invalid_request_error", "message": "…" }
4}

The Anthropic shape carries no code field. It matches the shape the Anthropic SDK parses.

/v1/decisions and /v1/systemone use the OpenAI shape with code set to the HTTP status as an integer, which the OpenRouter SDK requires there.

/v1/rerank and /v2/rerank return both, so Cohere and OpenAI-style clients can each parse it:

JSONjson
1{
2 "message": "…",
3 "error": { "message": "…", "type": "invalid_request_error", "code": null }
4}

A Claude model on an OpenAI endpoint still returns the OpenAI shape

cc/claude-sonnet-5 on /v1/chat/completions is an openai-node client that happens to want a Claude model. Keying the error shape on the model or the routed provider is the specific bug this behaviour exists to avoid.

Statuses

StatustypeOpenAI codeWhat it means
400invalid_request_error—Malformed body (one that is not a JSON object reads as one with no model), unknown provider prefix, a bare model id that names no provider (Claude Code and the Codex CLI excepted), a model id prefixed with another provider than the one your key, route or x-aile-provider pins (on a provider whose own ids carry no prefix, such as claude or codex), a refused field, or a bad x-aile-* value. The message names what it knows. On an x402 payment also: an attachment Aile cannot measure, n other than 1, a route or endpoint that takes no output cap, n_predict/n_cmpl on a self-hosted model, or an output budget above what was priced.
401authentication_errorinvalid_api_keyNo key, or a key that is not recognised.
402api_error—Not enough spendable balance (the message says how much and, on chat, where to add funds), a key over its spend limit, or partner credit refused. An attachment Aile cannot measure is held at the model's whole context window, and the message says so. On chat the body is a payment document whose error string says why.
403permission_error—The key exists but is not allowed to do this: disabled or expired, a stake key with no window or no usable fallback, or the only sharer left is you (every other sharer is tried first).
404not_found_errornot_foundUnknown model id, a model not served on the provider you named (the message says why), a chat model with no published list price, an unknown video job id, a path that serves nothing, or a chat path the provider you named does not serve (the message names both; refused before your key is checked, with nothing held).
409api_error—An Idempotency-Key replay. Deliberately does not fail over.
413invalid_request_errorrequest_too_largeBody over the size ceiling: 8 MiB, or 25 MiB on transcription, translation, image edits, /v1/images and OCR.
429rate_limit_errorrate_limit_exceededAile's own 429s carry retry-after, except a stake key's shared-pool refusal with no refill time. On self-hosted (local/) chat, a provider's 429 comes back with its status and body but not its headers, so it never carries retry-after. On the non-chat endpoints a provider's 429 is a 502 (below). A rate-window refusal adds x-ratelimit-* and x-aile-refused-by; the concurrency and guard refusals do not. See Rate limits.
500api_error—Fault on our side. The message is An unexpected error occurred (request <id>)., the id matching x-request-id; no internal detail is sent.
502upstream_error—Every sharer dialled refused, or the provider failed in a way that is not attributable to the request. A self-hosted machine that failed without answering says Self-hosted capacity failed (request <id>). Arrives as 503 (below).
503overloadedoverloadedNo sharer available for what you asked for (the message names the provider), or the relay is restarting, overloaded or paused, or its price list is still loading. Carries retry-after when a clock decides when it clears.
504api_error—No answer inside a deadline. Buffered chat names stream: true (unless the request already sent it) and adds x-aile-error: edge_deadline. Nothing is charged. Arrives as 503 (below).

502 and 504 arrive as 503

Cloudflare replaces an origin 502 or 504 with its own page, so /v1 sends both as 503 and carries the real code in x-aile-status. The body is the normal error body.

A keyed image or music request still running after 25 s is committed to 200 with x-aile-edge-hold, so a later failure arrives as a 200 carrying the error body (on a stream, as an error frame). The same holds for a streamed chat request; see Streaming.

Non-chat endpoints

Embeddings, images, audio, video, music, rerank, moderations, OCR and decisions use one account per request with no failover. When the provider refuses:

  • 400, 404, 409, 413, 415 and 422 pass through with the provider's words, sharer details removed. Fix the request.
  • A status that belongs to the sharer's account (401, 402, 403, 429, 5xx) is a 502 saying upstream X answered HTTP N; you were not charged, with none of the provider's text. On 401 to 403 it adds x-should-retry: false, because the same account refuses again. A 401 that marks the sharer's key dead, or a refusal that takes the sharer's account or model off sale (a spent balance), does not, since a retry picks another sharer.
  • A 2xx carrying nothing usable (no image, no audio, no results) is voided and answered 502.

Fields refused on chat

A sharer's account is billed for what the provider does, and Aile bills you only for what it can meter. A request field that would make the provider charge the sharer outside the metered usage is a 400 naming the field, before your key is checked or anything is held:

  • a file_id (or a file-search tool, or a hosted tool's container or file reference), in any dialect: it resolves in the sharer's workspace;
  • on OpenRouter: openrouter:* server tools, plugins other than the free PDF parser, models or route fallback, a :online or :nitro model, presets, and a provider.order or provider.only slug ending /fast, /priority or /ultrafast (premium-tier endpoints);
  • on a Claude model: Anthropic's advisor tool, and inference_geo other than global;
  • on hosts that bill hosted web search apart from usage (xkiro, muse-code): web_search, web_search_options, or a web_search* tool. A function tool you named web_search is fine;
  • on xai and xai-oauth: any tool the provider runs itself (web_search, x_search, code_interpreter and the like), web_search_options and search_parameters on /v1/chat/completions.

Fast mode (speed) is removed rather than refused on every chat endpoint (self-hosted local/ models excepted), and fallbacks on /v1/messages likewise; the reply says so in x-aile-speed-normalized and x-aile-fallbacks-normalized. See Headers.

Which are worth retrying

Retry: 429 (respect retry-after), 500, 502, and 503 after a delay. A 503 often means the pool was momentarily empty for that provider rather than that nobody serves it. Not when it carries x-should-retry: false; the OpenAI SDKs already honour that header.

Do not retry unchanged: 400, 401, 403, 404, 413. Retrying the same body produces the same answer.

Never blindly retry: 409. It means a request with that Idempotency-Key already exists. Read the original result instead.

Failover is already happening

On chat, by the time you see a 503, Aile has already tried several sharers. x-aile-attempts on a successful response tells you how many it took. A 503 with x-aile-status: 502 means sharers were dialled and every one refused; a plain 503 means none was eligible.

A retry loop of your own sits on top of a retry loop that already ran, so keep yours short and backed off rather than aggressive.

Note that pre-dispatch refusals are free: a sharer skipped for being in cooldown, having no payout wallet, or being saturated does not consume the attempt budget. Only real dials consume it. That is why a pool whose first several entries are unusable still reaches a healthy sharer behind them.

Actionable classifications

Some non-retryable failures carry a tag:

HTTPhttp
1x-aile-error: context_overflow

context_overflow maps to the OpenAI code context_length_exceeded. It means the request will not fit no matter which sharer takes it, so failing over is pointless. Shorten the input instead.

Served-model mismatch

HTTPhttp
1x-aile-verified: false
2x-aile-verified-model: <what the response actually claimed>

Emitted only on a confirmed mismatch between the model you asked for and the model the response identifies as. When it cannot be determined, these headers are silent rather than guessing; absence is not evidence of a match. See Verification.

Errors during a stream

Once the stream has started, an error arrives as a terminal SSE frame rather than an HTTP status. See Streaming.