Error codes
The error shape of each surface, the stable machine-readable codes, and what to do about each one.
Error shapes
The three surfaces each have their own error shape, but all of them carry a stable machine-readable identifier and a request id. message is for humans and varies by language, so never branch on it.
The gateway surface (/v1, /v1beta, /v1/videos) answers {error: {code, message}, request_id} with a real HTTP status. The console surface (/api/v1) answers a flat envelope. The private protocol (/server) always answers HTTP 200 and puts the failure in the body.
| Surface | Error shape |
|---|---|
| /v1, /anthropic, /gemini (including legacy /v1beta) | {"error": {"code", "message"}, "request_id"}, with the real HTTP status |
| /api/v1 | {"code", "error_code", "message", "request_id"}, plus violations on a 422 |
| /server | HTTP 200 with {"code": -1, "message": "…"}, wording byte-compatible with the legacy system |
{
"error": {"code": "insufficient_balance", "message": "The balance is not enough to hold this call."},
"request_id": "req_01J…"
}{
"code": 422,
"error_code": "invalid_time_range",
"message": "The time range is invalid.",
"request_id": "req_01J…",
"violations": []
}- The gateway calls it error.code and the console calls it error_code. Both take their values from the same catalogue and mean the same thing.
- One code always maps to one HTTP status. The reverse does not hold: a single status covers many codes.
Console envelope fields
A failing console endpoint answers with these fields. code is kept for earlier clients; branch and localise on error_code.
| Field | Type | Description |
|---|---|---|
| code | integer | The HTTP status code. |
| error_code | string | The stable machine-readable identifier, for example invalid_credentials. |
| message | string | A human-readable sentence that varies by language; do not branch on it. |
| request_id | string | Ties the response to the server logs; quote it when contacting support. |
| violations | array | Present only on a 422: the field-level failures, each shaped {field, rule, message}. |
Gateway error codes
| code | HTTP | Meaning | What to do |
|---|---|---|---|
| invalid_api_key | 401 | Key does not exist or is malformed | Check the key and the header |
| api_key_expired | 401 | Key has expired | Extend the expiry or create a new key |
| api_key_disabled | 403 | Key has been disabled | Enable it in the console or create a new one |
| account_disabled | 403 | The account is suspended | Contact support |
| ip_not_allowed | 403 | Source IP is not on the allowlist | Update the key's IP allowlist |
| region_blocked | 403 | Regional policy blocks the gateway | See the region notes, or use another region |
| model_not_allowed | 403 | The key's group does not allow this model | Change the group or the model |
| model_not_found | 404 | Model does not exist | Use the name from the model catalogue |
| model_not_supported | 422 | The model does not support this operation | Use an endpoint the model supports |
| insufficient_balance | 402 | Not enough balance to place the hold | Top up, or use a plan |
| quota_exceeded | 429 | Plan or resource-pack quota is used up | Wait for the window to reset, or renew |
| rate_limited | 429 | RPM or TPM exceeded | Back off per Retry-After |
| concurrency_exceeded | 429 | Concurrency exceeded | Lower concurrency, or upgrade the group |
| too_many_running_tasks | 429 | Too many waiting or running tasks for this user | Wait for one to finish and retry |
| content_filtered | 422 | Blocked by content safety | Adjust the input |
| invalid_request | 400 | Parameter error | Fix the request against the docs |
| invalid_json | 400 | The body is not valid JSON, or carries an undeclared field | Check the body |
| idempotency_conflict | 409 | The idempotency key was reused with a different body | Use a new key |
| task_already_completed | 409 | The task to cancel already finished upstream | Read the task's result |
| task_cancel_unavailable | 503 | The task's upstream account cannot be reached, so it cannot be cancelled now | Retry the cancellation later |
| idempotency_in_progress | 409 | The first request with this key is still running | Retry later with the same key |
| no_account_available | 503 | No upstream account is available right now | Retry later; the platform fails over automatically |
| upstream_error | 502 | The upstream returned an error | Read message, and quote X-Request-Id to support |
| upstream_timeout | 504 | The upstream timed out | Retry, or shorten the request |
| stream_interrupted | 502 | The stream was interrupted | Retry; whatever was generated is settled at its real usage |
| service_unavailable | 503 | A dependency is temporarily unavailable | Retry later |
| not_found | 404 | The resource does not exist, or belongs to someone else | Check the id and who owns it |
| asset_access_denied | 403 | The key's asset access is none but the request references an asset | Change the key to own or all in the console |
| reference_asset_unavailable | 404 | The reference asset is missing, unfinished, or outside the key's asset access | Check the asset id and the key's asset access |
| asset_not_deletable | 403 | A key whose asset access is own tried to delete a console upload | Delete it in the console, or with a key whose asset access is all |
- The private protocol maps these onto the legacy wording: insufficient_balance becomes user remainingAmount is not enough, too_many_running_tasks becomes get lock failed, and an upstream failure becomes call api error.
- A 4xx or 5xx failure is not charged. When a stream is interrupted, whatever was already generated is settled at its real usage.
Console error codes
| error_code | HTTP | Meaning | What to do |
|---|---|---|---|
| unauthenticated | 401 | Not signed in, or the session expired | Sign in again |
| invalid_credentials | 401 | Wrong identifier or password | Check them and retry |
| mfa_required | 401 | Two-step verification is on and the sign-in code was emailed | Send the emailed code in code |
| mfa_invalid | 401 | The sign-in code is wrong or expired | Request a new code and retry |
| captcha_required | 428 | A captcha challenge must be solved first | Fetch a challenge and send captcha_token |
| captcha_invalid | 422 | The captcha failed | Fetch a new challenge |
| account_locked | 423 | Too many failed attempts; the account is temporarily locked | Wait for the lock to lapse and retry |
| account_disabled | 403 | The account is suspended | Contact support |
| account_banned | 403 | The account is banned | Contact support to appeal |
| forbidden | 403 | This identity lacks the permission | Use an account that has it |
| email_exists | 409 | The e-mail is already registered | Sign in, or reset the password |
| weak_password | 422 | The password is too weak | Choose a longer, less predictable one |
| password_reused | 422 | The new password matches the current one | Choose a different one |
| verification_cooldown | 429 | Codes were requested too often | Wait for Retry-After |
| verification_exhausted | 422 | Too many wrong codes | Request a fresh code |
| invalid_time_range | 422 | The time range is invalid | Make sure start is before end |
| invalid_ledger_type | 422 | The ledger type is outside the enumeration | Check the type list |
| identity_already_linked | 409 | That provider account is linked to another user | Unlink it on the other account first |
| wholesale_invalid | 422 | The wholesale field combination is invalid | Check the required fields for that kind |
| wholesale_customer_not_bound | 422 | The customer is not bound to this agent | Ask an operator to bind the customer |
| wholesale_multiplier_out_of_policy | 422 | The agent multiplier is outside the configured range | Ask an operator to review the profile |
| agent_not_found | 404 | This account has no agent profile | Ask an operator to set one up |
| agent_suspended | 403 | The agent profile is suspended | Ask an operator to restore it |
- This table covers the common account-security, invoicing and agent-wholesale failures rather than every code. Anything not listed still follows the envelope and status conventions above.