Reference
Errors
Errors come back in OpenAI’s shape, with a stable code you can match on and a message written for people. A refused or failed call costs nothing.
Checked 26 October 2026
The shape
{
"error": {
"type": "rate_limit_error",
"code": "daily_cap",
"message": "This call needs up to $0.02 and the key has $0.01 left of its $2.00 daily cap, which resets at 00:00 UTC. …"
}
}Match on code, not on message: messages can be reworded, codes stay. type follows OpenAI’s, so SDKs raise the exception you expect.
Every code
| Status | Code | When | Fix |
|---|---|---|---|
| 401 | missing_key | No key was sent. | Send it as Authorization: Bearer sk-nokeep-…. Make one in the console, or try sk-nokeep-test first. |
| 401 | invalid_key | The key is wrong, or it was revoked. | Copy the key again from where you saved it; the console shows only its last four characters. Make a new one if it is lost. |
| 403 | account_frozen | Paid features are paused on the account the key belongs to. | Write to us from the contact page. |
| 429 | rate_limited | The key sent more than 120 requests in a minute (20 for the test key, per address). | Wait the seconds in Retry-After, then retry. |
| 429 | daily_cap | The call could pass the key’s daily cap. | Raise the cap in the console, lower max_tokens, or wait for 00:00 UTC (Retry-After says how long). |
| 402 | insufficient_credits | The account’s bought credits can’t pay for this call. | Top up from $5 in the console, or lower max_tokens. A plan’s credits stay in the app. |
| 400 | invalid_json | The body isn’t a JSON object. | Send Content-Type: application/json and a JSON object. |
| 413 | too_large | The request is over 12 MB. | Send pictures as links instead of data URLs, or send fewer at once. |
| 404 | model_not_found | The model id isn’t one of ours. | GET /v1/models lists the ids. Check for a typo or a missing -uncensored. |
| 400 | invalid_messages | messages is missing or empty, too long, has an unknown role, or a tool message has no tool_call_id. | Send 1 to 2,000 messages, each with a role of system, developer, user, assistant or tool. |
| 400 | unsupported_n | n is more than 1. | Send one request per reply you want. |
| 400 | invalid_reasoning_effort | The model doesn’t take that reasoning_effort. | DeepSeek takes none, low, high or max. GLM takes low or high. |
| 400 | unsupported_tool_choice | GLM got a named function or "required" as tool_choice. | Send auto or none to GLM; it picks its own tools. DeepSeek takes every form. |
| 400 | unsupported_input | A content part is a kind the model can’t read. | Send pictures to DeepSeek; GLM reads text only. |
| 400 | too_many_images | More than ten pictures in one request. | Send at most ten. |
| 422 | hard_limit | The request crosses one of the hard limits in the terms. | Nothing was charged. Drop the message from the history you send back, or the next call stops too. |
| 400 | rejected | The model couldn’t take the request as sent. | Check the parameters against the model’s list in Models. Nothing was charged. |
| 503 | busy | The model is busy. | Retry after the seconds in Retry-After. Nothing was charged. |
| 503 | model_unavailable | The model is offline on our side. | Use the other model for now; the status page shows when it is back. |
| 502 | upstream_error | The model failed before it wrote a word. | Retry in a moment. Nothing was charged. |
| 404 | not_found | The route doesn’t exist. | The API serves GET /v1/models, GET /v1/models/{id}, GET /v1/status and POST /v1/chat/completions. |
| 404 | api_closed | The API is switched off. | Try again later. |
| In a stream | Code | When | Fix |
|---|---|---|---|
| — | stream_cut | The model stopped before it finished, mid-stream. | What it wrote is billed, nothing more. Retry to get the rest, or continue from what arrived. |
Which ones to retry
- Retry
429 rate_limited,503 busyand502 upstream_error, after theRetry-Afterseconds when there are any. - Don’t retry the
400s,401s,402,404s or422: the same request gets the same answer. - A
429 daily_capwaits for 00:00 UTC. Raise the cap instead.