Model APIs

Request errors

On this page
  1. Response structure
  2. Status reference
  3. Handling request errors

Use the HTTP status to decide whether to correct a request, restore access, follow an existing job, or retry later. A failed HTTP request and a failed generation are separate events: a successful job read can report a failed job.

Response structure #

Problem responses use the same Error object as Model errors. status describes this HTTP response; code, when supplied, gives a stable reason. Show detail to the customer and keep request_id for support. Do not require a code or request id on every error: the captured 401 below has neither.

Field Type Required Description
code string No Machine-readable error code.…
type string Yes A URI reference identifying the problem type.
title string Yes
status integer Yes
detail string No
instance string No
job_id string No The job this refusal points at, so a client can follow it without reading detail.…
request_id string No

There is no separate runner-error object or error-type header; the problem object and the job's failure are the available error surfaces.

Status reference #

The example routes below declare these responses in the OpenAPI contract. 500 is covered by the route's default problem response and verified in its handler. Other routes can use the same status for a different refusal, so read their response contract too.

Status When it happens Retry unchanged? Example endpoint
400 Invalid input, unsupported fields, or a malformed upload. A generation may supply validation or a remembered moderation code. No; correct the request. See the new-model rollout exception. POST /assets
401 Authentication is missing, invalid or expired. No; obtain a valid credential first. GET /me
402 Insufficient credits, a member budget ceiling, or a plan requirement. No; resolve the balance, budget or plan. POST /generate/image
403 The credential or organization role lacks permission. No; resolve access with the owner or administrator. POST /assets/{id}/share
404 A resource is unknown or not visible in the current scope. No; check its id and scope. GET /jobs/{id}
408 The long-poll window closed before the job became terminal. Yes; wait again on the same job id. GET /jobs/{id}/wait
409 Duplicate generation submission; other endpoints also use it for busy or conflicting state. Follow the supplied job_id; do not create a replacement automatically. POST /generate/image
410 A share link expired, was revoked, or points to trashed/deleted media. No; ask the owner for a new usable link. GET /share/{token}
413 The uploaded file exceeds the accepted size. No; reduce the size or use the appropriate upload flow. POST /assets, POST /assets/uploads
422 A generation or cost-confirmation gate refused the request. No blind retry; inspect code. Re-quote for confirmation_rejected. POST /generate/image
429 A rate limit was reached; generation routes also use it for concurrency or quota. Yes, after the supplied delay or reset time, with backoff. GET /share/{token}
500 The server could not complete its operation, such as a job lookup failure. Retry a read with backoff; establish whether a write took effect before repeating it. GET /jobs/{id} (default problem response)
502 An upstream model or service failed. Yes for a temporary failure, with backoff and the same generation key. POST /generate/video/enhance-prompt
503 A required service or feature is temporarily unavailable. Yes with backoff; persistent configuration unavailability needs support. POST /jobs/{id}/sse-ticket

This unauthenticated request returned the following production response on 2026-09-21.

JSON401 Unauthorized — production response
{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401,
  "detail": "valid authentication is required"
}
Field Meaning
type Problem type URI.
title, status The request was unauthorized; this is not a credit refusal.
detail Authenticate before retrying.

A repeated generation returned this production 409. The missing code is deliberate: status and job_id fully identify the duplicate.

JSON409 Conflict — production response
{
  "detail": "this exact request was already submitted as job 35b6ff8d-0c78-440b-bdb3-bfe476b56d76 less than 5m0s ago and has not been billed twice — check it with GET /jobs/35b6ff8d-0c78-440b-bdb3-bfe476b56d76. To run it again anyway, resubmit with a different Idempotency-Key header.",
  "job_id": "35b6ff8d-0c78-440b-bdb3-bfe476b56d76",
  "request_id": "localhost/7bnUUXx7b2-007291",
  "status": 409,
  "title": "Conflict",
  "type": "about:blank"
}
Field Meaning
job_id The already accepted generation to read or wait for.
request_id This refusal's correlation id for support.
status, title, type The duplicate was refused with 409; there was no second bill.
detail Explanation for the customer; use job_id directly instead of extracting it from this text.

Handling request errors #

Retry 408, 429, 502 and 503 with bounded exponential backoff and jitter. A 408 from wait retries only the wait, not generation submission. On 429, pause your queue so parallel workers do not immediately consume the next available slot together. Stop after a bounded number of attempts and preserve the last problem and request id.

Do not automatically retry 401, 402, 403 or 404. They require a valid credential, sufficient balance or entitlement, permission, or the correct resource and scope. Resolve 400, 410, 413 and 422 using the status table rather than repeating the same input.

Header Where it is supplied How to use it
Retry-After Public share-link 429 responses use 60 seconds. OAuth token/revocation 503 responses also declare it. Do not retry before the indicated delay. Generic HTTP clients should also handle the standard HTTP-date form.
Retry-After-Reset Generation quota refusals when a reset time is available. Wait until that RFC 3339 UTC instant before submitting again.
Neither Some concurrency and transient service errors do not include a retry header. Use bounded exponential backoff with jitter; a missing header does not mean retry immediately.

If you already have a job id, keep following that job through temporary read errors. Read failure.code and failure.credits_refunded only when the generation itself fails; a failed status request does not prove that happened. See Model errors for typed refusals and job failures.