Skip to main content
Every versioned JSON error uses the same typed envelope:
Switch on error.type, not on the human-readable message. Messages are written for humans and may be reworded; the type is contract. Every error includes a stable more URL that links directly to its catalog entry. A documented type can add structured recovery data inside error; for example, validation.prompt_integrity_review_required adds a review challenge. The same envelope is returned across every endpoint, including Session and Run operations.

Namespaces

The prefix tells you who has to act. User-correctable errors carry enough detail to fix the request, so a model driving the API can self-correct. Internal failures return an opaque incident reference instead of a stack trace or secret-bearing context.

Error registry

validation.payload_too_large always names a specific documented ceiling. Request and payload limits lists every one of them, and which of them refuse with a 413 rather than a 400. validation.range_too_large is its read-side counterpart, and the distinction is worth holding: the request is well formed, but your Workspace’s data density exceeds what the read can decode. It is never a truncated answer. Whether a narrower range fixes it depends on which read you called, and the message says which case you are in — a grouped read replays the whole requested range, so narrowing works, while the Workspace-total read replays a roughly 48-hour tail anchored to as_of rather than to your request, so narrowing does not reduce it. runtime.attestation_invalid appears only on the connected-runtime observation path: a signed observation batch whose Ed25519 signature, runtime registration, or placement does not verify. Ordinary API clients never produce it. runtime.provisioning_suspended settles a Run after several consecutive provisioning failures in a short window: the sandbox provider kept refusing or never became ready, so the platform stops burning provider attempts for a short cooldown instead of retrying forever. It clears itself — the next Run after the cooldown provisions normally, and a single successful start resets the count.

Retry guidance

Retry only the types marked Yes above. Retry those with exponential backoff and jitter, capping the number of attempts. Everything else is a decision, not a transient failure: the request, the configuration, or an approval has to change before it can succeed. Retrying a policy.denied or a runtime.invalid_transition fails identically every time. Three retryable types are worth calling out because they are easy to misread:
  • validation.idempotency_in_progress means another request carrying the same Idempotency-Key is still in flight. Back off and retry the identical request; you receive the first request’s result rather than causing a second mutation.
  • runtime.observation_gap means execution evidence arrived out of order. The Run is intact and the write is safely repeatable.
  • memory.backend_unavailable means the versioned MemoryStore backend cannot serve the operation and the write was not applied. When an enabled backend is unhealthy, back off and retry. In the hosted alpha the versioned surface is intentionally disabled pending D7, so retries cannot make those fenced endpoints succeed. A document body that retention refuses is a different answer entirely: it returns 403 policy.denied, never this type, so no amount of retrying stores it.
memory.read_only is never retryable, and one of its causes is easy to mistake for a race: a write against an archived MemoryStore returns 403 memory.read_only, not a 409. Archiving is not a transient state, so retrying never clears it.

Errors that need an upstream change

CLI exit codes

Scripted callers get a stable, closed failure-class axis: the CLI maps every error to one process exit code, keyed on the kind of failure rather than the specific error.type. This lets a script branch on $? without parsing JSON. 130 and 143 are reserved for SIGINT/SIGTERM. Exit codes signal the kind of failure only. A run’s actual result still comes from the event log, and a task that ran but failed its rubric is a successful transport (exit 1 as a usage-level outcome), not a transport error.

Next steps

Quickstart

Drive your first Run end to end and see these error types in context.

API reference

Browse the endpoints and shapes that emit this error envelope.