Errors & retries
The error body, every error code with its HTTP status, and when to retry.
Every error answer has the same JSON body:
JSON
{
"error": {
"code": "INVALID_INPUT",
"message": "wait must be an integer from 0 to 60 (seconds).",
"retryable": false,
"field": "wait"
}
}| Field | Description |
|---|---|
error.code | Stable, machine-readable code (table below). Branch on this, not on the message. |
error.message | Human-readable explanation. The wording can change. |
error.retryable | true when the same call can succeed later without changes. |
error.field | The input field at fault, when there is one (snake_case, for example items[1].model_id). |
error.retry_after_seconds | How long to wait before retrying, when known. Sent together with a Retry-After header. |
error.suggestions | MODEL_NOT_FOUND only: close matches, each { id, name, type }. |
request_id | Top level, next to error: present when the request was recorded before it failed. Check GET /v1/requests/{request_id} before retrying. |
Errors of a finished request (status failed, or a failed item of a batch) use the same error object inside the request object.
#Error codes
| HTTP | Code | Meaning |
|---|---|---|
| 400 | INVALID_INPUT | A field is missing, has the wrong type or value (see field), or the body is not valid JSON. |
| 400 | URL_NOT_ALLOWED | A URL (for example webhook_url or source_url) is not https, carries credentials, or points to a non-public address. |
| 400 | INVALID_RUN_TOKEN | A run behind the request could not be identified. |
| 400 | MODEL_REQUIRED | A model id is missing (for example in a batch item). |
| 400 | MODEL_KIND_MISMATCH | The model does not produce the requested kind (for example a video model in an image batch item). |
| 400 | MODEL_NOT_ALLOWED | The model is not one of AITOPIA's recommended models for this operation; pick one of the suggestions. |
| 400 | DUPLICATE_ITEM | Identical batch items with a model that takes no seed; vary the prompts. |
| 401 | UNAUTHENTICATED | Missing, malformed, unknown or revoked key (Authentication). |
| 401 | KEY_SESSION_EXPIRED | The key's aitopia.ai session ended. Sign in to aitopia.ai to reactivate the key. |
| 402 | INSUFFICIENT_CREDITS | Not enough credits on the account. |
| 402 | KEY_CREDIT_CAP_REACHED | The key's monthly credit cap would be passed (Billing). |
| 402 | OVER_BUDGET | The plan costs more than max_credits. |
| 404 | MODEL_NOT_FOUND | No model with this id; see suggestions. |
| 404 | NOT_FOUND | No such request in your account, or no such endpoint. |
| 404 | TOOL_NOT_FOUND | The requested operation does not exist. |
| 409 | PRICE_CHANGED | The price changed since the dry run. Nothing was run or charged; run a new dry run. |
| 409 | PRICE_UNKNOWN | The price could not be checked before running, so nothing ran (for example an edit step without a fixed price). |
| 409 | PLAN_EXPIRED | The plan_token expired (plans are kept 1 hour and run once), was already used, or belongs to another file or instruction; run a new dry run. |
| 413 | FILE_TOO_LARGE | The body or file is over the size limit (File uploads). |
| 413 | INPUT_TOO_LARGE | The model input is over the size limit (the message names the limit). |
| 422 | PLAN_INVALID | No valid edit plan could be built. |
| 422 | ASSET_UNREACHABLE | An input file could not be downloaded (unreachable or too slow). |
| 422 | NOT_SUPPORTED | No AITOPIA model, agent or tool can do this edit. |
| 429 | RATE_LIMIT | Too many requests (Rate limits). |
| 429 | RUN_LIMITED | A generation limit on the account. Retry only after retry_after_seconds when it is given; otherwise read message. |
| 429 | QUEUE_LIMIT_EXCEEDED | Only a few runs can be active at once per account; wait for running jobs to finish. |
| 500 | INTERNAL_ERROR | An unexpected error on our side. |
| 502 | UPSTREAM_5XX | A service behind the API failed. |
| 502 | UPSTREAM_UNCERTAIN | The run may have started and may be charged. Check the request_id and your balance before retrying. |
| 503 | MODEL_UNAVAILABLE | The model (and its fallbacks) is unavailable right now. Nothing was run or charged. |
| 503 | SERVER_RESTARTING | The server is restarting. Always retryable. |
| 503 | SESSION_UNAVAILABLE | The sign-in service is temporarily unreachable (not a problem with your key). Always retryable. |
| 504 | TIMEOUT | An upstream step timed out. |
A code not listed here is answered with HTTP 502. Treat it like UPSTREAM_5XX and follow retryable.
#Codes inside a request
These appear in the error of a request or a batch item, not as an HTTP error status:
| Code | Where | Meaning |
|---|---|---|
STATUS_CHECK_FAILED, RUN_STALE, KEY_SESSION_EXPIRED | open request (queued / running) | A status check did not get through; the request stays open (details). |
OUTPUT_INCOMPLETE, NO_OUTPUT | failed | The run finished but its output was missing or unreadable. |
UPSTREAM_RUN_FAILED | failed (request or batch item) | The model provider ran the job and reported a failure; message gives the provider's reason. Follow retryable. The sandbox returns it for X-Sandbox-Outcome: failed / partial. |
RUN_INTERRUPTED, RUN_LOST | failed | A background run was interrupted, for example by a server restart. |
FAILED | failed | The run failed without a more specific code; see message. |
#When to retry
The retryable flag in the body is authoritative. As a rule:
retryable: true: retry the same call. Waitretry_after_secondswhen present (or theRetry-Afterheader), otherwise back off exponentially (for example 1 s, 2 s, 4 s ... up to a minute). Unless the body says otherwise,429,503and504answers are retryable;SERVER_RESTARTINGandSESSION_UNAVAILABLEalways are.retryable: false: change something first (fix the input, add credits, sign in to aitopia.ai, raise the cap). Retrying the same call gives the same answer.
Submits are not idempotent: the API has no idempotency keys, and every accepted submit is a new, separately charged run. Before you retry a submit that failed with a 5xx or a network error:
- If the error body has a
request_id,GET /v1/requests/{request_id}first: the run may exist. - On
502 UPSTREAM_UNCERTAIN(retryable: false) check the request and your balance; do not retry blindly. - On a network error with no answer at all, check
GET /v1/account/balancebefore submitting again.
GET calls (models, requests, balance) are safe to retry at any time.