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.code is 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.error is 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.
  • requestId names this request in the server's logs. It is also returned in the X-Request-Id response header, and you may send your own X-Request-Id to have it used instead. Quote it when you report a problem.

Status codes

StatusMeaning hereWhat to do
400The 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.
401No 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.
402A 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.
403Authenticated, 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.
404Not found, or not yours: another organization's row is the same 404 as a missing one.Check the uid and the caller's organization.
409A 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.
423Locked: 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.
429Rate 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.
503Temporarily 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.
5xxA 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.

What's next

On this page