# Error Codes

> Diagnose ScaleMax authentication, model access, quota, rate-limit, provider, timeout, and request-validation errors.

Errors follow the OpenAI shape:

error:

```json
{
  "error": {
    "message": "Human-readable summary",
    "type": "error_category",
    "code": "machine_readable_code",
    "param": "field_name_if_applicable"
  }
}
```

Some errors add fields to `error` so a client can act without parsing the message: `model_not_in_plan` adds `allowed_models` (models this key can use, best first) and `upgrade_url`; balance errors add `top_up_url` and the amounts. On `/v1/messages` the same refusals use the Anthropic shape (`{"type":"error","error":{"type":…,"message":…}}`) with these fields on `error`.

Every error response also carries an `X-Request-Id` header. Include it when reporting issues to [ScaleMax support](https://docs.scalemax.pro/docs/support). For symptom-first fixes, start from [Troubleshooting](https://docs.scalemax.pro/docs/troubleshooting).

## Codes

| HTTP | Code | Type | Meaning | What to do |
| --- | --- | --- | --- | --- |
| `401` | `invalid_credentials` | authentication_error | The API key is missing, malformed, revoked, or being sent to the wrong credit/token billing surface. | Use the base URL returned by setup: API-credit keys normally use /v1, API-token keys use /token/v1, and unified Auto keys use https://api2.scalemax.pro/v1. Then check the Authorization header; replace the key only if both are correct. |
| `403` | `key_expired` | permission_error | The API key was valid but has now expired. | Request a renewed key from ScaleMax support. |
| `403` | `key_disabled` | permission_error | The API key is suspended or disabled, or a feature (for example video generation or Voice) is switched off on it. A model outside your plan is model_not_in_plan, not this. | Check the key in dashboard Settings. If it should work, contact ScaleMax support with the request id. |
| `403` | `model_not_in_plan` | permission_error | The model you asked for is not included in this key’s plan (its model families, the models selected for the key, or a model launched after the key was bought). The key itself works. The error lists models you can use in allowed_models and links to plans in upgrade_url. | Switch to a model from allowed_models (the full list is on the dashboard Models page), or buy a pack that includes the model. Claude Code refused on claude-haiku-4-5: set ANTHROPIC_DEFAULT_HAIKU_MODEL to one of your models, or run npx scalemax@latest. |
| `401` | `wrong_billing_surface` | authentication_error | The key is valid but was sent to the base URL of the other billing type (a token key on /v1, or a credit key on /token/v1). | Use the base URL named in the error message (it is also shown for the key in dashboard Settings). The key does not need replacing. |
| `429` | `rate_limit_exceeded` | rate_limit_error | You exceeded the per-key requests-per-minute limit. | Back off and retry with jitter. See Rate Limits for your specific cap. |
| `429` | `concurrency_limit_exceeded` | rate_limit_error | Shown in your request log. The key already had its maximum number of requests running at once. The API answers rate_limit_exceeded with a message naming the cap. | Wait for a running request to finish, honor Retry-After, then retry. Nothing is charged for the refused request. |
| `429` | `balance_temporarily_reserved` | rate_limit_error | Another in-flight request is temporarily reserving this key’s available balance. | Wait for that request to finish, honor Retry-After, then retry once. |
| `429` | `limit_reached` | quota_error | You used your full token budget for this period. | Top up the existing key with a compatible token pack before retrying. |
| `402` | `insufficient_credit` | quota_error | The key does not have enough available credit or tokens to start this request. The error says what is left, what the request needed and where to top up (top_up_url). | Top up the existing key. If another request is still running, wait for it to settle before checking the balance. |
| `402` | `balance_too_low_for_output` | quota_error | Shown in your request log. The balance left could not cover the longest reply the request allowed (max_tokens). The API answers insufficient_credit, and names a max_tokens that fits when a shorter reply would. | Lower max_tokens (or max_output_tokens) to the figure in the error, or top up the key. |
| `402` | `free_model_requires_paid_account` | quota_error | Free models are not available on trial keys. | Buy any pack (or top up once) to use free models on the key, or pick a model your trial includes. |
| `400` | `invalid_request` | invalid_request_error | The request body failed schema validation. | Check the parameter list for the endpoint. Common causes: missing model, empty messages, malformed tool_calls. |
| `404` | `model_not_found` | invalid_request_error | The model id isn't in the catalog. | Use GET /v1/models for API credit or GET /token/v1/models for API tokens to see the current list. |
| `400` | `context_length_exceeded` | invalid_request_error | The combined input exceeds the model context window. | Trim conversation history or switch to a model with a larger window. |
| `400` | `bridge_unsupported_text_format` | invalid_request_error | A /v1/responses request asked for a structured output format (text.format, for example json_schema) that this model cannot enforce. | Remove text.format and ask for the shape in the prompt, or switch to a model that supports structured output. |
| `400` | `responses_not_supported` | invalid_request_error | This model is not served on /v1/responses. | Call the same model on /v1/chat/completions. |
| `400` | `tool_output_missing_call_id` | invalid_request_error | A /v1/responses tool result (function_call_output) did not name the call it answers. | Send each tool result with the call_id of the function_call it answers. |
| `400` | `image_input_unsupported` | invalid_request_error | The request carries an image and the chosen model can't read images. | Remove the image or switch to a model with image input; the error message names some you can use. |
| `502` | `provider_unavailable` | api_error | The model provider is temporarily unavailable for this request. | Retry with exponential backoff, or switch to another available model. |
| `502` | `upstream_error` | api_error | The upstream provider returned an error or timed out. | Retry with exponential backoff. If persistent, try a different model. |
| `504` | `upstream_timeout` | api_error | The provider took too long to respond. | Retry. For long generations consider streaming. |
| `500` | `internal_error` | api_error | Unexpected error inside the gateway. | Retry. If it persists, contact support with the request id from the response headers. |

## Retry behavior

- For a retryable `429`, honor the `Retry-After` header. Do not create parallel retries. The caps and headers behind a 429 are described in [Rate limits](https://docs.scalemax.pro/docs/rate-limits).
- `5xx` responses are safe to retry with capped exponential backoff and jitter. Stop retrying after response content has started streaming.
- Most `4xx` responses are not retryable. The explicit exception is a temporary `429`. Authentication, permission, validation, and exhausted-quota errors require corrective action first.
