code. This page explains the body, which part of it to write logic against, what each status family means, the handful of rejections that arrive as plain text, and how to retry POST /v1/runs safely. It is for anyone writing error handling against the API. Every code has its own page in the problem catalog.
The error envelope
violations is omitted when the model returned no document at all.
Match on the code, not the message
- Write logic against
code. It is the contract. The same code means the same thing on every route. - Use the status to classify, not to decide. The status tells you the family: your request, your credential, your account, or the service. Two codes with the same status can need different fixes:
402 insufficient_creditsneeds a purchase,429 organization_token_quota_exhaustedneeds a smallermax_output_tokensor a new period. - Treat
messageas diagnostic text. Log it, show it to a developer, never parse it. For example, thedeadline_exceededmessage says “before a route was chosen” even when the model call is what timed out. - Handle unknown codes. Fall back to the status family below when you meet a code your client does not know.
Status families
The service fails closed: when it cannot check your credential, reach its data store, or confirm a model answer, it refuses with a 503 rather than guessing.
When to retry
The status decides whether a retry can help:
Pick your own backoff, for example 1, 2, 4 and 8 seconds with jitter, and stop after a few attempts.
Retrying POST /v1/runs
POST /v1/runs requires an Idempotency-Key. Which key you send on a retry depends on what you got back:
See Idempotency for key design and Error handling for a complete retry loop.
Plain-text rejections
A few rejections come from the HTTP layer before a route’s own validation runs. Their body istext/plain, not JSON, and has no request_id. The x-request-id response header is still present.
Some bodies add
: and a detail, such as the name of the unknown field.
The 400, 413, 415 and 422 rows apply to the keys, usage and billing routes; the 404 and 405 rows apply everywhere. The runs routes turn the same body and query problems into JSON: 400 invalid_body and 413 body_too_large.
Parse defensively. Read the body as text, try to decode it as JSON, and fall back to the status when that fails.
Errors on POST /v1/runs, in order
POST /v1/runs checks a request in a fixed order and stops at the first failure, so fixing one error can reveal the next:
- Credential:
401,403 no_active_organization,503 auth_not_configuredortrust_keys_unavailable. - Body:
400 invalid_body,413 body_too_large. - Scope:
403 scope_deniedwithoutruns_write. Idempotency-Key:400 idempotency_key_requiredorinvalid_idempotency_key.- Prompt shape, then the schema or question set, then capability hints:
400 invalid_body,invalid_verdict_schema,invalid_decision_questions. - Input size:
413 input_too_largeabove 262,144 estimated tokens for a decision, 64,000 for a verdict. - Data store:
503 database_unavailableornot_configured. - Period quota:
429. - Idempotency:
409 idempotency_conflictwhen the key was used with a different body. - Credits:
402 insufficient_credits. - Routing and the model call:
503,504, or413 input_too_largewhen the input is over the model’s own limit.
429 or 402.
Related
- Problem catalog - every code, its status, and whether a retry helps.
- Error handling - a retry loop you can copy.
- Idempotency - when to reuse and when to replace a key.
- Request ids - trace one failed request.
- Limits - the bounds behind 400 and 413 errors.