Errors and retries
Classify failures correctly and retry only when another attempt can help.
Do not retry every non-success response. Blind retries increase cost, duplicate work, and can turn a small outage into a larger one.
Response classes
| Status | Meaning | Typical action |
|---|---|---|
400 | Request rejected by endpoint logic | Fix the request; do not retry unchanged. |
401 | Missing, invalid, or revoked credential | Refresh or replace the credential. |
403 | Authenticated but not authorized | Fix scopes, role, visibility, or sharing. |
404 | Resource absent or intentionally hidden across an org boundary | Verify the identifier and organization context. |
409 | State or idempotency conflict | Read the detail and reconcile state. |
413 | Declared or received upload is too large | Reduce the file; do not retry unchanged. |
415 | Unsupported request media type | Send the documented Content-Type. |
422 | Request body or parameters failed schema validation | Fix the payload; do not retry unchanged. |
429 | Rate or capacity limit | Back off and respect retry guidance. |
5xx | Server or dependency failure | Retry with bounded exponential backoff. |
Malformed API payloads answer 422, not 400 — request validation runs before
endpoint logic, so a missing field, a wrong type, or an out-of-range value is a
422. Treat 400 and 422 the same way when retrying: both mean the request
itself is wrong.
Do not confuse that synchronous response with output-schema verification. An
agent run is admitted before its output exists. If an otherwise successful
response later fails the agent's Draft 2020-12 output contract, the start request
does not retroactively become a 422; the run ends with status=failed,
verification_status=verification_failed, and a schema-validation error. Fix
the agent output or its configured contract before retrying.
A run started while the workspace is at its concurrency limit is not refused:
it is accepted with status=pending and a queued_since time, and it starts on
its own when a slot frees. Only a full queue answers 429, with Retry-After.
A queued run is checked again when it gets its slot. If something its start
depended on changed while it waited, it ends failed with an error_code that
names what: dequeue.agent_paused, dequeue.actor_not_member (the person who
started it left the workspace), dequeue.actor_unavailable (the person who
started it is still a member but can no longer start work: their account was
deactivated, locked or deleted, or they were made a viewer),
dequeue.trigger_disabled (its schedule or
webhook was turned off), dequeue.thread_closed or dequeue.thread_paused
(the thread's request waits for it to resume), dequeue.turn_requester_unavailable
(whoever sent the request a thread turn answers can no longer start work in the
workspace). None clears on its own, so don't retry until that has changed back.
Daily caps and budget stops also answer 429, usually without Retry-After,
because they clear at midnight UTC or need an operator to act. Besides the
workspace's own daily cap (daily.cost_cents), which applies only when the
owner has set one, a run can meet the daily free allowance of the workspace's
owner (daily.allowance_cents). Every run in the
workspace draws on that allowance, whoever or whatever starts it, and every
workspace the owner has shares it. A run can also meet the platform's daily
limit on free usage (daily.platform_cents). An owner who joined through an
invitation and no longer shares a workspace with their inviter has no free
usage until their account is approved (account.needs_approval); that one
doesn't clear at midnight.
A run whose AI model provider rate limits its requests is not failed either.
It pauses with status=paused_limit_exceeded and
error_code=provider.rate_limited, and its limit_detail.resets_at is when it
continues on its own, from where it stopped. That time comes from the
provider's own reset signal, and one wait lasts at most 15 minutes. Don't start
the work again while it waits. If the provider rate limits the same step five
times in a row, or the wait would pass the run's time limit, the run fails;
start it again later.
Retry policy
Use exponential backoff with jitter, a maximum attempt count, and an overall deadline. Preserve the same idempotency key when retrying the same execution start or when an upload response was lost.
Retry 5xx, and 429 after the indicated delay. Do not retry validation, permission, or visibility failures until something material changes. Default any status you do not recognize to non-retryable rather than retryable.
Artifact upload failures
An artifact becomes reusable only after the upload answers 201. These
failures never leave a ready artifact:
| Status | Upload meaning | Next action |
|---|---|---|
400 | The received byte count differs from X-Upload-Size, or its lowercase SHA-256 differs from X-Content-SHA256. | Fix the body or headers and use a new idempotency key. |
409 | The key names different upload metadata, the original upload is still active, or the original artifact failed or was deleted. | Never change the request under the key. Honor Retry-After for an active identical upload; use a new key after failure or deletion. |
413 | The declared or streamed bytes exceed the upload limit. | Reduce the file and use a new key. |
415 | Content-Type is not exactly application/octet-stream. | Fix the media type before sending bytes. |
429 | Upload rate, capacity, or organization storage quota is exhausted. | Honor Retry-After when present; otherwise wait for capacity or free storage. |
If the connection disappears before a response, retry the exact request with
the same key. A completed upload replay returns the original ready artifact. An
upload still being processed answers 409 with Retry-After. If the server
already recorded the attempt as failed, the replay answers 409; generate a
new key only then. Never reuse the key with a different filename, description,
size, checksum, or body.
Diagnostics
Record the HTTP status, request or correlation identifier, endpoint, attempt number, and safe error detail. Redact Bearer tokens, trigger tokens, secrets, and sensitive payloads.