Error Codes
Error format
Section titled “Error format”All errors follow the OpenAI-compatible error format:
{ "error": { "message": "A human-readable description of the error", "type": "error_type", "param": "field_name", "code": "error_code" }}The param and code fields are optional and may be null.
The one exception is POST /v1/messages, which answers in Anthropic’s envelope so that Anthropic SDKs and Claude Code read it natively:
{ "type": "error", "error": { "type": "invalid_request_error", "message": "A human-readable description of the error" }, "request_id": "…"}code and param are included inside error when set. A request that exceeds the model’s context window is a 400 whose message begins prompt is too long and carries the capability_rejected: prompt_too_long token, which Claude Code’s automatic compaction looks for. The status codes below apply to both shapes.
Status codes
Section titled “Status codes”| Status | Type | Description |
|---|---|---|
400 | invalid_request_error | Request validation failed — malformed JSON, missing required fields, or invalid parameter values. |
401 | authentication_error | Missing or invalid API key / JWT token. |
402 | billing_error | Billing account balance is too low to process the request. Add credits to continue. |
403 | authorization_error | Valid credentials but insufficient permissions for the requested resource. |
404 | invalid_request_error | Resource not found — unknown route, a model your organization cannot use, or referenced resource (e.g. file_id) doesn’t exist or belongs to a different organization. |
410 | invalid_request_error | Resource gone — a referenced file is past its expires_at, or the endpoint has been removed. |
429 | rate_limit_error | Rate limit exceeded. How to retry depends on the bucket — see Rate Limits. |
499 | client_closed_request | Client disconnected before the response finished. Returned for aborted streams. |
500 | server_error | Unexpected error while serving the request. |
502 | server_error | Failed to reach the model inference layer. |
504 | server_error | Model did not respond before the request timeout. |
500, 502 and 504 all carry type: "server_error" — read code to tell them apart. A 500 carries no code.
Common error codes
Section titled “Common error codes”The code field gives a more specific reason than the type alone. Notable ones:
| Code | Status | When |
|---|---|---|
invalid_value | 400 | A request field has an invalid value — a bad mime type or purpose, an image_url / video_url / file_id needing a capability the chosen model lacks, a content part type the model does not support, a tool result with no matching tool call, a tool_choice asking for a tool that is not in tools, or a max_tokens (max_completion_tokens when a chat request sends that, max_output_tokens on /v1/responses) at least as large as the model’s context window. param names the field |
invalid_media_url | 400 | A media URL does not meet the URL requirements, for example an http URL, an IP address, or an internal hostname. Use a public https URL, a file_id, or a base64 data: URL. param names the field |
context_length_exceeded | 400 | Request exceeds the model’s max context window. Shorten the prompt or lower the requested output tokens |
unsupported_value | 400 | The request uses something that is not available: previous_response_id or an item_reference input item on /v1/responses (response objects are not stored), or an input item type or tool type the model does not support. param names the field, and the message names the type when it is a standard one |
file_not_found | 404 | Referenced file_id doesn’t exist or isn’t owned by your organization |
file_expired | 410 | Referenced file_id is past its expires_at |
endpoint_removed | 410 | The endpoint no longer exists, such as /v1/completions. The message names the endpoint to use instead |
model_not_found | 404 | The model is not an exact model id, or the model is not priced in your billing currency. GET /v1/models lists chat models and GET /v1/videos/models lists video models |
model_deprecated | 404 | The model was retired. The message names the model to use instead |
model_access_denied | 404 | The model exists, but your organization does not have access to it. Contact support@aiand.com to request access |
invalid_api_key | 401 | Missing, malformed, or unknown API key |
rate_limit_exceeded | 429 | A rate limit was exceeded. Model-bucket rejects set X-RateLimit-Policy; authentication throttles carry only Retry-After |
insufficient_credits | 402 | Balance too low |
upstream_error | 502 | Could not reach the model inference layer, or its response was unreadable |
timeout | 504 | Model did not respond before the request timeout |
client_closed_request | 499 | Client disconnected before the response finished |
Turning reasoning off
Section titled “Turning reasoning off”A model can turn reasoning off only if its published levels include none. Sending reasoning_effort none, reasoning.effort none, or on /v1/messages a thinking block with type disabled, to a reasoning model that does not publish none, returns 400 invalid_request_error:
Model '<name>' cannot disable reasoning: suppressing it needs reasoning_effort 'none', which this model does not publish. Supported values: <levels>. Use '<level>' for the least reasoning.<level> is the lowest of that model’s published levels. A model without the reasoning capability ignores these fields instead.
Other reasoning level errors
Section titled “Other reasoning level errors”A level other than none that a model doesn’t list runs at the next listed level up, or the model’s highest, instead of failing; an unlisted none is the 400 above. A value outside the effort vocabulary, such as ultra, gets Model '<name>' does not support <field> '<value>'. Supported values: <levels>. A reasoning model that lists no levels at all answers any level with Model '<name>' lists no reasoning levels, so it cannot apply <field>.
Handling errors
Section titled “Handling errors”from openai import OpenAI, APIError
client = OpenAI( api_key="sk-your-api-key", base_url="https://api.aiand.com/v1",)
try: response = client.chat.completions.create( model="google/gemma-4-31b-it", messages=[{"role": "user", "content": "Hello!"}], )except APIError as e: print(f"Status: {e.status_code}") print(f"Message: {e.message}")The OpenAI SDK automatically parses the error response and raises typed exceptions. For 429 errors with X-RateLimit-Policy, handle the reject by bucket: back off (honoring Retry-After) on time-based rejects, but for concurrency rejects let in-flight requests drain instead of retrying. An authentication throttle has no policy and should honor Retry-After. See Rate Limits.