Melious

Chat Completions, Responses and Messages return endpoint-specific error bodies; System One has its own envelope, described at the end. Account-level throttling uses a separate flat response, described below.

Shape

The body depends on which endpoint you called. Chat Completions and Responses share the OpenAI envelope; Messages uses the Anthropic one.

Chat Completions (/v1/chat/completions):

{
  "error": {
    "message": "The model does not exist or you do not have access to it.",
    "type": "invalid_request_error",
    "param": null,
    "code": "model_not_found"
  }
}

Responses (/v1/responses) uses the same {"error": {...}} shape with its own type and code values — see its table below. Messages (/v1/messages):

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "..."
  },
  "request_id": "..."
}

type is the coarse classifier, code the specific one, and param names the offending request field when there is one. Match on type and code, never on message — messages are for humans and may be edited. On Responses, code carries the public code when one exists and otherwise repeats the type. On Messages, error.code is optional, and request_id repeats the request-id and x-request-id headers that every Messages response carries. code is open-ended — a code you don't recognize is the internal error name in lowercase; fall back to type for it.

The common ones

What you're most likely to see, per endpoint.

Chat Completions

StatustypecodeWhat to do
400invalid_request_errorinvalid_request_errorMalformed request or missing field — param names it.
400invalid_request_errormodel_not_capableThe model lacks the capability asked for (vision, tools, JSON mode).
400invalid_request_errorcontext_length_exceededTrim the prompt or pick a model with more headroom.
400invalid_request_errorcontent_policy_violationRejected by the safety filter. Don't retry verbatim.
401authentication_errorinvalid_api_keyNo key, malformed, or unknown. Fix the Authorization header — see Authentication.
403authentication_errorauth_insufficient_scopeThe key can't call this endpoint. Use a key with access or contact support.
403invalid_request_errorinference_free_tier_unavailable:free isn't available for this model or account. Drop the suffix.
404invalid_request_errormodel_not_foundUnknown model ID. Check GET /v1/models.
429rate_limit_exceededrate_limit_exceededThrottled. Back off per Retry-After — see Rate limits.
429billing_errorbilling_insufficient_balance, insufficient_quotaNo eligible balance. Not a throttle — see below.
429billing_errorbilling_hold_creation_failedWe couldn't reserve the hold. Transient — retry once.
429invalid_request_errorinference_free_tier_rate_limitedThe :free window is used up. Wait the Retry-After seconds or drop the suffix.
500server_errorsystem_internal_errorUnexpected failure on our side. Retry once, then send the X-Request-ID response header to support.
503server_errorserver_error, provider_error, timeoutTransient. Retry with backoff.

One status, two meanings: a throttle says rate_limit_exceeded; a billing refusal says billing_error. The refusal's code varies with which balance came up short — billing_insufficient_balance or insufficient_quota — so classify on the type. The exception is the :free throttle, which carries type: invalid_request_error with the code above; match that one on code. Backing off won't change your balance. The same billing refusal is a 403 on Responses and Messages.

Responses

StatustypeMeaning
400invalid_request_errorMalformed request (including previous_response_id), capability or context mismatch.
401authentication_errorMissing or invalid API key.
403permission_denied_errorBilling refusal, or the key can't call this endpoint.
404not_found_errorUnknown model ID.
429rate_limit_exceededThrottled. Back off per Retry-After.
503server_errorTransient. Retry with backoff.

Two statuses on this endpoint don't use the shape above. A missing or invalid key (401) and a key without the inference.chat scope (403) return a flat body: {"code": "AUTH_1008", "message": "...", "request_id": "..."} — AUTH_1007 for no key, AUTH_1008 for an invalid key, AUTH_1015 for a missing scope. Match on code. A body that isn't valid JSON gets the same flat shape with a 400.

Messages

StatustypeMeaning
400invalid_request_errorMalformed request, bad content block, capability or context mismatch.
401authentication_errorMissing or invalid API key.
403permission_errorBilling refusal, or the key can't call this endpoint.
404not_found_errorModel not found.
429rate_limit_errorThrottled. Back off per Retry-After.
503api_errorTransient. Retry with backoff.

Every Messages response carries request-id and x-request-id with the same value, and error bodies repeat it as request_id — any of the three is the id to quote to support.

Model access

model_not_allowed (403) means the same thing on all three endpoints: the key isn't allowed this model. Use a key with access to it, or pick a different model.

The account limiter's flat 429

For these three endpoints, account-level throttling returns a flat 429 body with no type:

{
  "code": "RATE_LIMIT_EXCEEDED",
  "message": "Too many requests. Please try again later.",
  "details": { "retry_after": 3 }
}

Classify it on code: "RATE_LIMIT_EXCEEDED" and back off per the Retry-After header. The window it enforces, and the headers that expose its state: Rate limits.

Streaming requests

With stream: true, the model, your key's access to it, and the tools, tool_choice and response_format fields are checked before the response starts — those refusals are normal HTTP errors with the statuses above. Everything that happens after that arrives inside the stream, behind an HTTP 200 and without a Retry-After header:

RefusalChat Completions error.typeResponses error.codeMessages error.type
Concurrency or daily caprate_limit_exceededrate_limit_exceededrate_limit_error
No eligible balancebilling_errorpermission_denied_errorpermission_error
Context window exceededinvalid_request_error, code context_length_exceededinvalid_request_errorinvalid_request_error
No provider, provider failure, timeoutserver_errorserver_errorapi_error

Read the type before you resend: a cap or a provider failure is worth a delayed retry; a balance or context refusal is not. A natural-language model name or auto on Chat Completions skips the pre-check, so every refusal is in-stream for those requests. Frame shapes: Streaming.

When to retry

You gotRetry?How
429 throttle (rate_limit_exceeded / rate_limit_error, or the flat RATE_LIMIT_EXCEEDED)YesWait the full Retry-After; without one, back off exponentially. Cap your attempts.
429 :free window (inference_free_tier_rate_limited)YesWait Retry-After, or drop the :free suffix.
429 / 403 billing refusal (billing_insufficient_balance, insufficient_quota)NoTop up or change plan. The OpenAI SDKs retry this twice unless you set max_retries=0.
429 billing_hold_creation_failedOnceTransient on our side.
503 server_error, provider_error, timeout, api_errorYesBack off; honor Retry-After when present. Stop after a few attempts.
500OnceThen send the request id to support: the X-Request-ID header, or on Messages the body's request_id — same value.
400, 401, 403 (scope or model access), 404NoFix the request, key or model first. content_policy_violation: don't resend the same input.
In-stream error after output startedNot automaticallyA resend is a new, separately billed request and may repeat tool calls. See Streaming.
In-stream error before outputBy its typeSame rules as the matching HTTP row; no Retry-After header is available.

The OpenAI SDKs retry every 429 and every 5xx twice by default, including a billing refusal. Set max_retries=0 on the client and retry yourself on type, or accept two wasted attempts before the exception reaches you.

System One errors

/v1/systemone has its own error envelope: lowercase codes such as invalid_request and auth_insufficient_scope, an X-System-One-Error-Code header, and a request_id in both the body and X-Request-ID. See System One.

Response-level backoff headers: Rate limits. API-key access: Authentication. Picking a model with the capability your request needs: Models.

On this page