Errors
The per-code list and the typed error.details shapes are in the published OpenAPI schema — browse them in ReDoc or fetch /v1/openapi.json. This page covers the envelope, the discriminate-on-code rule, the handling strategy, and a few codes whose behavior the schema can't fully express.
Every non-2xx response uses the unified envelope:
{
"error": {
"code": "<machine_readable_snake_case>",
"message": "<human-readable summary>",
"request_id": "<server-assigned id>",
"details": "<optional, code-specific>"
}
}
error.code is the authoritative discriminator. Never parse error.message. The same request_id appears on the X-Request-Id response header and on every server log line for the request — quote it in support tickets.
error.details is typed per code in the OpenAPI schema (e.g. validation_failed, task_not_supported_by_model, model_not_found, sync_too_large each carry a structured payload). Switch on code first, then read details; codes without a typed shape carry only the human-readable message and should be treated as opaque.
Notable codes
Most codes are self-explanatory from the OpenAPI schema. A few have behavior worth noting:
504(no envelope): a sync request past the upstream read timeout is terminated by the edge proxy with the proxy's body, not the unified{error: {...}}envelope (see Limits). Retry withPrefer: respond-async.404 not_foundon cross-account access: accessing another caller's job returns404, not403, to prevent id enumeration.413 sync_too_large: emitted only by the compositefind-genes-and-predict-expressionworkflow when submitted synchronously above 50,000 bp; resubmit withPrefer: respond-async. No/v1/tasks/{task}/predictendpoint emits it. See Limits.429 too_many_requests: comes from three paths — the per-key concurrency cap, the per-key rate cap, or the edge per-IP cap. All emitRetry-After; the application paths also emitRateLimit-*headers. On the edge path,error.request_idis an edge-assigned identifier (32 hex chars) rather than a UUID, but still correlates with the edge access log. See Limits.
Handling errors
Three buckets:
- Retryable transient (
429,503): honorRetry-After; if absent, exponential backoff capped at ~30 s. - Permanent (other
4xx): surfaceerror.messageto the user; do not retry.422 validation_failedmessages are usually deterministic and safe to echo verbatim. - Server bug (
5xxother than503and504): capturerequest_idand contact us. One retry is fine; tight loops are not.
504 is the exception to bucket 3: it carries no envelope and means the sync request outran the proxy window, so retry it with Prefer: respond-async rather than treating it as a server bug (see the note above).
Back to the workflow: REST API guide · Tasks.