Errors and status codes
The error envelope, what each HTTP status means here, and which failures to retry.
Every failed request returns a JSON envelope with a human-readable message, a stable
machine-readable code when there is one, and a request id. This page explains how to read it;
the full list of codes is the generated error-code catalog.
The envelope
{
"error": {
"error": "A row with that value already exists.",
"code": "CREATE_DUPLICATE",
"requestId": "3f9a1c7e-2b54-4d8a-9f10-6c2e7b5a4d31"
},
"requestId": "3f9a1c7e-2b54-4d8a-9f10-6c2e7b5a4d31"
}error.codeis the identifier to branch on. It does not change when the wording of the message improves. It is absent on generic failures, notably an ordinary policy denial.error.erroris the message, written for a person. Show it or log it; don't parse it.error.details, present on some codes, carries structured context, such as the metric that hit its limit or how long to wait.requestIdnames this request in the server's logs. It is also returned in theX-Request-Idresponse header, and you may send your ownX-Request-Idto have it used instead. Quote it when you report a problem.
Status codes
| Status | Meaning here | What to do |
|---|---|---|
400 | The request is malformed or fails validation: a missing required column, a field the API does not take (ROW_FIELD_NOT_ACCEPTED), a reference uid that names no row (ROW_REFERENCE_NOT_FOUND). | Fix the request. The message names the field. |
401 | No usable credential. AUTH_TOKEN_EXPIRED and AUTH_TOKEN_INVALID mean the access token is no good; API_KEY_INVALID covers a missing, malformed, unknown, revoked or expired key alike; MFA_REQUIRED means sign-in needs a second factor. | Refresh the token pair and retry once; otherwise sign in again. |
402 | A plan limit or feature: SUBSCRIPTION_LIMIT_REACHED, FEATURE_NOT_INCLUDED, AI_SPEND_CAP_REACHED. | Not retryable as-is. The account's plan or limits must change. |
403 | Authenticated, but not allowed. A plain policy denial carries no code. Coded 403s name a specific rule, such as CROSS_PLANE_FORBIDDEN or APPROVAL_SELF_APPROVAL. | Grant the action to the caller's role, or don't make the call. |
404 | Not found, or not yours: another organization's row is the same 404 as a missing one. | Check the uid and the caller's organization. |
409 | A conflict with current state: a unique value already taken (CREATE_DUPLICATE), a step already decided, an idempotency key reused with a different body or still in progress. | Re-read, then decide. |
423 | Locked: a table locked against this operation (TABLE_LOCKED), an account that is paused or restricted, an app mid-move. | Not a client bug. Retrying won't help until the state changes. |
429 | Rate limited (RATE_LIMITED for the per-IP limit), or too many agent runs at once (AGENT_RUN_CONCURRENCY_LIMIT). | Wait for Retry-After, then retry with backoff. |
503 | Temporarily unavailable. APP_WAKING means an idle app is being woken by this request; APP_RESTORING that it is being restored. | Wait for Retry-After, then retry. |
5xx | A server-side failure. | Retry idempotent requests with backoff; report persistent ones with the request id. |
A pause is not an error
A call that reaches a step needing approval answers 202 with pending_approval. Nothing failed:
the work is recorded and waiting for a person. See Approvals.
Retrying safely
Retry 429 and 503 after the Retry-After interval, and transient 5xx with exponential
backoff. Don't retry 400, 402, 403, 404 or 423 unchanged.
A write can be made safe to retry: send an Idempotency-Key header with a unique value on
POST, PATCH or DELETE to a table, or on an agent tool call. A repeat with the same key and
the same body within 24 hours returns the stored response instead of writing again. See
Idempotency.