Skip to content
Version: Current

What to do with an error

Every error body carries acumen_code, acumen_class, retryable, retry_after_ms and request_id. The code is the same string on every door, so a client can branch on it without parsing prose. Read the class first, then retryable and retry_after_ms, then the code. A retry without reading those three fields is a guess.

The generated error code index is the full list with the source line of each code. This page is the action for each code, grouped by the class it belongs to.

Class Status Retryable Retry-After What to do
auth 401, 403 no none Fix the credential. A retry with the same credential fails the same way.
rate_limit 429 yes at least 1s Wait for retry_after_ms, then retry. If it repeats, lower the request rate or raise the key’s limit.
budget 402 no window reset, when the code has one The window is spent. Wait for the reset, raise the cap, or use a key with budget left.
model_unavailable 404, 403, 503, 410, 400 some only for a stale catalog Check the model id, the key’s model allowlist and the seat health.
contract 400, 413, 415, 412 no none The body is the problem. Fix the field named in errors[].
idempotency 409, 422 only in flight 1s for in flight Wait when the request is in flight. Do not reuse a key with a different body.
upstream 502, 503, 504 yes from the vendor, clamped to 6h The seat failed. Retry with backoff; if it repeats, check that seat’s credential.
gateway 500, 501, 503, 400 some 1s on the retryable 503s Retry a 503 with retry_after_ms. Do not retry a 500, a 501 or a 400.
not_found 404 no none The path or the object does not exist. Check the route and the id.

Nothing in this class is retryable: the credential or the session has to change.

  • auth_missing: send an Authorization: Bearer header with a virtual key.
  • auth_invalid, auth_revoked, auth_expired: mint a key, or rotate the one you hold.
  • auth_scope: the key does not carry the scope for this route. Request one with the scope, or use a key that has it.
  • auth_process_token: the process token is for the control plane, not the model doors.
  • auth_session: the browser session is not valid. Sign in again.
  • creds_seat_side_only: vendor credentials are accepted only by the seat, not by a client call. Call the gateway with a virtual key and let the seat hold the vendor credential.

Every code in this class is retryable and carries retry_after_ms.

  • rate_rpm: requests per minute.
  • rate_tpm: tokens per minute.
  • rate_concurrency: concurrent requests against one key.
  • rate_tenant: the whole tenant, shared by its keys.
  • rate_ip: the source address, used when no key authenticated the request.
  • limit_exceeded: the aggregate limit across all dimensions. Wait for retry_after_ms and retry.

Wait for retry_after_ms and retry. A burst that keeps hitting the same code is a pacing problem: spread the work, or raise that dimension’s limit on the key.

Nothing in this class is retryable until the window resets or an operator changes the cap.

  • budget_key_daily, budget_key_weekly, budget_key_monthly: the key’s own cap. The window reset is the retry time. Raise the cap or wait.
  • budget_project, budget_tenant, budget_seat, budget_pool_exhausted: the shared budget is spent, not the key’s. An operator raises the pool; a client retry does not.
  • budget_reservation_failed: the reservation could not be held, so the request was refused before it cost anything. Retry once after the next billing tick; a repeat is an operator issue.
  • budget_unavailable: the budget service is not reachable. Retry with backoff; if it repeats, the operator must restore the service.
  • wallet_floor_refused: the balance is at or below the configured floor. Top up, or lower the floor deliberately.
  • wallet_balance_stale: the balance cache is stale. Retry once; if it repeats, the operator must check the wallet service.
  • model_unknown, model_not_found: call GET /v1/models and use an id from the list.
  • model_not_allowed: the key’s model allowlist excludes it. Change the key or the model.
  • model_no_eligible_seat: no seat can serve it now. Retryable, with no Retry-After. Check the capacity page before you retry in a loop.
  • model_catalog_stale: the catalog has not refreshed. Retry after the interval in retry_after_ms.
  • model_deprecated: gone by design. Move to the model’s replacement.
  • model_capability_unsupported: the model does not support this door or capability. Choose a model that does.

Nothing in this class is retryable: the same body fails the same way.

  • contract_unsupported: the request declares a contract version this door does not serve. Check contract in the response and use a supported version.
  • schema_invalid, payload_too_large, unsupported_media_type, precondition_failed: fix the request. The errors[] array names the field and a JSON Pointer.
  • idempotency_in_flight: wait one second and retry the identical request.
  • idempotency_conflict: the same key was used with a different body. Use a new key.
  • idempotency_stream_completed: the stream already finished; do not replay it.
  • idempotency_replay_unavailable: the replay window closed. Resend the request with a new key.

The seat failed, not the client. Every code here is retryable, with a Retry-After taken from the vendor and clamped to six hours.

  • upstream_error, upstream_timeout, upstream_rate_limited: retry with backoff. A repeat on the same seat is that seat’s fault; exclude it or fix its credential.
  • upstream_empty, upstream_protocol: the seat answered, but not with a usable body. Retry once, then report the seat and the request_id.
  • upstream_auth: the vendor rejected the seat credential. Retryable because a retry can route to another seat; on a pinned seat retryable is false, because the same seat with the same credential cannot succeed. The seat needs an operator.
  • store_unavailable, overloaded, draining: retry after retry_after_ms.
  • store_schema_mismatch: retry after retry_after_ms once. A repeat means the running binary and the store disagree, which is an operator fix, not a client one.
  • internal, not_implemented: do not retry. Report the request_id.
  • secrets_not_accepted: a secret value was sent where a reference belongs. Send the credential id, not the credential.
  • seat_reauth_required, seat_credential_missing, seat_credential_unavailable, cli_oauth_disabled, base_url_rejected, wallet_balance_stale: the seat or the wallet needs an operator. Retrying does not change it.
  • budget_unavailable: the budget service is not reachable. Retry with backoff; if it repeats, the operator must restore the service.
  • byok_unavailable: the BYOK credential is not configured or not reachable. An operator must configure the credential; a client retry does not change it.
  • resource_not_found: check the id. The route exists, the object does not.
  • route_not_found: check the path and the door. Nothing is served there.

Include the request_id, the acumen_code, the door path and the time. Do not include a key value. A key id is enough to find the request; the key itself is a secret.