Errors
Every refusal says what happened and, for a person, what to do. A refused or failed call is not charged. Branch on the status and the machine-readable code; show the message to a person if you like, but don’t parse it.
The shape of an error
Section titled “The shape of an error”The shape follows the format of the endpoint you called, so each SDK raises its usual exceptions.
Chat Completions, Responses and Speech: the OpenAI shape. The reason is in error.code.
{ "error": { "type": "billing_error", "code": "api_wallet_empty", "message": "Your API wallet does not have enough credits for this request. ..." }}Messages: the Anthropic shape, with Anthropic’s types. The specific reason is in error.message.
{ "type": "error", "error": { "type": "rate_limit_error", "message": "This API key is limited to 60 requests a minute. ..." }}A few refusals send error as a plain string: images and video, an unknown key on Chat Completions and Models, and an unknown model on Chat Completions. Some add a message.
{ "error": "unauthorized" }{ "error": "unknown_model", "model": "gpt-4o", "known": ["glm-5.3-flash", "..."] }So read the code like this:
const body = await response.json();const code = typeof body.error === 'string' ? body.error : body.error?.code ?? body.error?.type;Every endpoint
Section titled “Every endpoint”These come from the key, the wallet and the limits, and can happen on any endpoint.
| Status | Code (OpenAI shape) | Messages type | Meaning | What to do |
|---|---|---|---|---|
| 401 | unauthorized (string on Chat Completions, Models, images, video) |
authentication_error |
Missing, unknown or revoked key | Check the key and the header; it may have been revoked |
| 402 | api_wallet_empty |
billing_error |
The API wallet cannot pay for this request | Add funds, or lower max_tokens |
| 402 | key_spend_cap_reached |
billing_error |
The key reached its monthly cap | Raise or remove the cap, or use another key |
| 403 | account_suspended |
permission_error |
The account is suspended | Contact us |
| 413 | request_too_large |
request_too_large |
The body is too big | Send less at once: fewer or smaller images, a shorter history |
| 429 | rate_limited |
rate_limit_error |
The key passed its requests per minute | Wait Retry-After seconds, or raise the key’s limit |
| 429 | too_many_concurrent_requests |
rate_limit_error |
8 requests already in progress on the account | Wait for one to finish |
| 429 | (no JSON body) | More than 10 requests a second from one IP address | Slow down | |
| 503 | overloaded (type overloaded_error) |
overloaded_error |
Aderra is busy receiving other large requests | Retry after Retry-After (5) seconds |
Chat: Completions, Messages, Responses
Section titled “Chat: Completions, Messages, Responses”| Status | Code | Endpoint | Meaning | What to do |
|---|---|---|---|---|
| 400 | invalid_json / invalid json |
all | The body is not JSON | Fix the body |
| 400 | unknown_model / unknown model <id> |
all | Not an Aderra chat model | Use an id from GET /v1/models |
| 400 | unsupported_n |
Completions, Responses | n is not 1 |
Send n: 1, or leave it out |
| 400 | max_tokens must be a positive integer |
Messages | max_tokens is 0, negative or not a number |
Send a positive integer, or leave it out |
| 400 | max_output_tokens must be a positive integer |
Responses | Same, for max_output_tokens |
Same |
| 429 or 400 / 5xx | upstream_error (with the upstream status as a number in code) / api_error |
all | The model is busy or failed | Try again in a few seconds. Not charged |
| 502 | upstream_unreachable / api_error |
all | The model could not be reached | Try again. Not charged |
Images and video
Section titled “Images and video”| Status | error |
Meaning | What to do |
|---|---|---|---|
| 400 | invalid_json, missing_prompt |
No JSON object, or an empty prompt |
Fix the body |
| 400 | invalid_size |
size is not a string |
Send a string |
| 400 | unsupported_size |
The model is not sold at that size; allowed lists the sizes |
Use one of allowed |
| 400 | invalid_price_limit |
maxPriceMicro is not a string of digits |
Fix it |
| 400 | unknown_model |
Unknown model while maxPriceMicro is set |
Check the name in /v1/usage/prices |
| 400 | no_reference_image |
Edits: no recent image on the account | Generate or send an image first |
| 400 | invalid_duration |
Video: duration is not a whole number above 0 |
Fix it |
| 400 | image_required |
Video, image mode: there is no recent image |
Generate or send an image first |
| 400 | invalid_mode, invalid_image_count, invalid_reference_video_count, invalid_source_video, invalid_end_frame, invalid_video_origin, invalid_explicit |
Video: a field has a value Aderra does not take | Fix it; see Video |
| 400 | end_frame_requires_two_images, reference_required, source_video_required |
Video: the mode found nothing to use at that position | Make or send the image or clip first |
| 400 | reference_images_unavailable, video_mode_unavailable |
Video: the model cannot take images as references, or does not make that mode | Follow the message |
| 402 | price_limit_exceeded |
The image costs more than maxPriceMicro |
Raise the ceiling or pick another model |
| 422 | refused_blank, image_content_refused |
The image model refused the prompt | Reword it. Not charged |
| 422 | video_content_refused |
The video model refused the prompt | Reword it. Not charged |
| 502 | image_failed, video_failed |
The model failed | Try again. Not charged |
Speech
Section titled “Speech”| Status | code |
Meaning |
|---|---|---|
| 400 | invalid_json, model_not_found, invalid_input, input_too_long, input_too_long_for_format, invalid_voice, unsupported_format, invalid_speed, unsupported_language |
A field is wrong; param names it |
| 401 | unauthorized |
No valid key (also on GET /v1/audio/voices and GET /v1/audio/models, which take any Aderra key) |
| 402 | insufficient_credits (type insufficient_quota) |
The wallet cannot pay for this input |
| 403 | api_key_required |
A terminal key was used |
| 429 | provider_busy |
The voice service is busy. Not charged |
| 502 | provider_failed |
The voice could not be made. Not charged |
See Text to speech errors for what to do about each.
Terminal keys
Section titled “Terminal keys”A terminal key follows your plan, so it can get the plan’s refusals as well: insufficient_credits when the plan’s credits run out, context_length_exceeded when a conversation is longer than the plan’s context window, burst_window_exhausted when the plan’s message window is used up, and plan_required on the Free plan. See Error messages. API keys never get these.