# Error Codes

Source: https://aiand-docs-staging.pages.dev/errors/

## Error format

All errors follow the OpenAI-compatible error format:

```json
{
  "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`](/api/messages/#errors), which answers in Anthropic's envelope so that Anthropic SDKs and Claude Code read it natively:

```json
{
  "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

| 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](/reference/rate-limits/#429-responses). |
| `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

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](/capabilities/vision/#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

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`:

```text
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

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

```python
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](/reference/rate-limits/#429-responses).
