OP Inference

Errors

The error envelope and every error code.

Every error, on every route, has the same shape. Branch on code, never on message: the code is stable and the message is for people.

The envelope

{
  "error": {
    "code": "rate_limited",
    "message": "the provider is rate limiting; try again shortly",
    "kind": "rate_limit",
    "scope": null,
    "type": "rate_limit_error",
    "param": null,
    "request_id": "req_...",
    "retry_after_ms": 2000
  }
}
FieldAlways presentMeaning
codeYesWhat went wrong. One of the codes below
messageYesA human-readable explanation. It may change; do not parse it
kindYesThe class of failure: terminal, unavailable, rate_limit, timeout or unknown
scopeYesWhat the error is about: request, model, route, or null
typeYesThe matching OpenAI error type, so an OpenAI SDK raises its usual exception. Do not branch on it
paramYesReserved, always null. When a refusal is about one field, the message names it
request_idNoThe request's id, also sent as the x-op-request-id header
generation_idNoPresent once a generation existed
retry_after_msNoHow long to wait before retrying. When present, a Retry-After header carries the same wait in whole seconds
attemptsNoOne entry per endpoint tried, each with its status and kind
state, usage, costNoOn 409 idempotency_conflict only. See Idempotency

Retry or fix

The kind tells you what to do:

  • terminal: retrying the same request gets the same error. Fix the request, the key or the account first.
  • rate_limit, unavailable, timeout: retry with backoff. Honour Retry-After when it is sent.
  • unknown: our failure. Retry once, then contact support with the request_id.

Before you see a retryable error, the gateway has usually already tried every other endpoint that serves the model. See Fallbacks.

Codes

CodeStatusKindMeaning
invalid_request400terminalThe body or a field is not valid. The message names the field
policy_conflict400terminalThe request asks for something the key's policy does not allow, such as a looser retention class or another region
unsupported_capability400terminalThe request asks for a feature this API does not offer
context_length_exceeded400terminalThe input is longer than the model's context window
unauthorized401terminalThe API key is missing, unknown, expired or deleted
budget_exceeded402terminalThe request would cross the key's monthly spend cap. See Key restrictions and spend caps
insufficient_credit402terminalThe account has no prepaid credit left. See Credits and billing
forbidden403terminalThe key may not make this request: a model outside its set, or an address outside its IP ranges
moderation_refused403terminalThe request was refused on content grounds
model_not_found404terminalGET /v1/models/{id} has no model with this id, or a preset names a model that does not exist. See /models
no_endpoint_available404terminalNo endpoint can serve the request: the model id is unknown, or no endpoint passes the request's filters right now. The message lists what excluded them
job_not_found404terminalNo job has this id for your account
run_not_found404terminalNo workflow run has this id for your account
idempotency_conflict409terminalA chat request with this Idempotency-Key is in progress or finished
payload_too_large413terminalThe request body is too large
rate_limited429rate_limitToo many requests right now. See Rate limits
internal_error500unknownThe gateway failed to complete the request
provider_unavailable502unavailableNo endpoint could complete the request
provider_empty_response502unavailableThe endpoint answered with no output
provider_payment_required502unavailableThe endpoint could not take the request. Not about your account
provider_unauthorized502terminalThe endpoint refused the gateway. Not about your key. Retry later
snapshot_expired503unavailableThe gateway's configuration is out of date. Retry shortly
upstream_timeout504timeoutThe endpoint did not answer in time
request_timeout504timeoutThe request did not finish within the time allowed for it
retention_expired504terminalA zdr media job did not finish within 24 hours and was discarded. See Data retention
client_disconnectednonenoneYou closed the connection. Recorded in your usage, never sent to you

A failed media job carries the same code and message in its error field. See How media jobs work.

Errors during a stream

An error before the first chunk is an ordinary HTTP error with the envelope above. Once a stream has started, the status is already 200, so a failure arrives as a last chunk with an error field, then data: [DONE]. Check every chunk for error. See Streaming.