Errors
A refused call answers with an HTTP status that fits what went wrong and one JSON body shape:
{
"error": {
"type": "invalid_request_error",
"code": "validation_failed",
"message": "The request payload failed validation.",
"param": "text",
"details": [{ "param": "text", "message": "String should have at least 1 character" }],
"request_id": "c5a04c28ab76af26eb320eced12e30f0"
}
}
| Field | Always there | What it is |
|---|---|---|
type | yes | The family of the error, derived from the HTTP status (below). |
code | yes | A stable, machine-readable code. Branch on this. |
message | yes | A short English sentence for people. Show it or log it; never branch on it — its wording may change. |
param | no | The request field the error is about, when there is one: always on 422, and on other errors about one field, such as a name already taken or a file too large. |
details | no | On 422 only: one entry per offending field, with its dotted path (attachments[0].file_id) and what was wrong. |
request_id | yes | Identifies the request in our logs; also sent as the X-Request-Id header. Include it when you contact support. |
Types
type | HTTP status |
|---|---|
authentication_error | 401 — the credential is missing, invalid, expired or revoked. |
permission_error | 403 — the credential is valid but may not do this. |
rate_limit_error | 429 — too many requests, too much at once, or out of credits. |
api_error | 5xx — something failed on our side. |
invalid_request_error | Every other 4xx — the request itself cannot be served. |
Codes
New codes may be added over time. Treat a code you do not know by its HTTP status family.
| Status | Codes |
|---|---|
400 | bad_request |
401 | invalid_secret, invalid_token, project_disabled, token_expired, user_disabled |
403 | permission_denied, project_disabled, user_disabled |
404 | file_expired, file_not_found, generation_not_found, not_found, project_not_found, session_not_found, user_not_found |
405 | method_not_allowed |
409 | call_in_progress, conflict, idempotency_conflict, idempotency_in_progress, session_busy, session_ended, session_not_realtime, session_not_taskable |
410 | endpoint_retired — see Versioning |
413 | file_too_large, payload_too_large |
422 | unsupported_media_type, validation_failed |
429 | insufficient_available_credits, insufficient_credits, rate_limited |
500 | internal |
502 | upstream_error |
503 | service_unavailable |
The API reference lists, on every operation, the statuses it can answer with.
Handling errors
401— get a new credential. For a user token: issue a new one (token_expired), or stop calling for that user (user_disabled,invalid_tokenafter a revocation).409 session_busy— a task is still running in that session. Wait for its end event, or stop it, then send the message again.409 idempotency_in_progress— the first request with thatIdempotency-Keyis still being handled. Wait for the number of seconds in theRetry-Afterheader, then retry the same request with the same key: it answers with the first request's answer.409 idempotency_conflict— the key was already used for a different request. Do not retry: send the new request with a new key. See Idempotency.429 rate_limited— wait for the number of seconds in theRetry-Afterheader, then retry. See Rate limits.429 insufficient_credits— the project's balance is used up. There is noRetry-After: retrying will not help until credits are added.insufficient_available_creditsmeans the project still has credits, but they are all held by work already under way.5xx— retry with exponential backoff. For a request that starts work — a message, a generation — send anIdempotency-Key, so a retry never starts it twice.
A task that has already started reports its own failure on the event stream, in its
task.failed frame, rather than as an HTTP error; see Event streams.