Skip to content

Errors and recovery ​

Failures appear at three layers: the HTTP request, a task inside a run, and a run or conversation as a whole. Each is read in a different place and recovered differently.

FailureWhere to look
API requestThe HTTP status and the error envelope
TaskThe run's task read: status and error: { key, detail? }; the task_status event
RunThe run's status and attention: { reason, blocked_task_keys }; the attention_required event
Candidate answerThe turn's variant status; a failed or canceled candidate is terminal, not an answer

Request errors ​

Controller-handled failures use one JSON envelope on both API families:

json
{ "error": { "code": "unauthorized", "message": "Unauthorized" } }
StatusCodeCauseWhat to do
400bad_request, parameter_missing, parameter_invalidMalformed JSON, a missing root, or a malformed, nonpositive or above-maximum scalarCorrect the request; values are never silently clamped
401unauthorizedThe credential is missing, expired, revoked, fenced or on the wrong plane — deliberately indistinguishablePresent a live credential of the right plane, or reconnect
403not_authorized, administrator_required, user_not_administrableStanding refused by name: a read principal writing, a non-administrator on an admin route, a target the caller cannot administerAct as a principal with the required standing
404not_foundA scoped-finder miss; an inaccessible or tombstoned record reads identicallyCheck the id and your access
409stale_object, already_claimed, not_addressed_here, task_not_claimable, execution_in_progress, budget_window_overlap, cost_unit_conflict, idempotency_envelope_mismatch, …The operation conflicts with current stateRefetch, then decide; never retry blindly
410execution_details_prunedRetention removed the execution's detailRead the retained text; post a new input instead of regenerating
422validation_failed, invalid_steps, schedule_finished, unknown_result_upload, …The body is well-formed but refused by the resourceCorrect the field the message names
429rate_limitedThe resource's budget is spentHonor Retry-After (a whole number of seconds)
5xx—An unhandled application or upstream failure; the body may be JSON, non-JSON or emptyClassify by status; follow the resource's readback or idempotency behavior before repeating a mutation

A failed connection or 5xx does not prove that a write was rejected. Where a resource accepts Idempotency-Key, replay the same key and body: workspace, conversation, fork, input and store-entry creation replay the original status and body with Idempotency-Replayed: true.

Task failures ​

Task statuses: waiting | needs_approval | running | dispatched | awaiting_input | completed | failed | canceled | timed_out | uncertain | skipped. A client that predates a status treats an unknown one as live. A failed task carries error.key:

KeyCauseRecovery
approval_deniedA deny rule, or rules mode with no allowData the model reads; adjust rules for later turns
approval_expired (timed_out)Nobody approved within 24 hoursThe next round reads it; approve sooner next time
tool_failed, tool_timeout, tool_uncertainThe tool could not run, exceeded its deadline, or its executor expired with no resultuncertain means the effect may have happened; a person's retry or abandon decides
tool_not_served, executor_revokedNo eligible executor, or the addressed executor was removedSelect an eligible runner or reconnect the executor
provider_http_error, provider_error, provider_overloaded, provider_transient_exhausted, attempt_budget_spentProvider failure or exhausted route budgetOnly classified retryable exhaustion can advance through the captured fallback list; abnormal generation finishes remain terminal
provider_model_unavailableProvider HTTP 401, 403 or 404Fix credentials, enablement or the model reference
provider_context_overflow, context_overflowThe request did not fitArms a compaction repair rather than a retry
model_refusedClassifier refusal or content protectionA classifier refusal may advance to the next permitted captured candidate; a content block cannot
model_route_spentA retry named an already refused or exhausted routeChoose a different unspent route permitted by the captured intent
model_capability_unavailableThe model lacks something the request needs, e.g. toolsChoose another model
await_failed, await_timeoutA parked question or wait failed or expiredDecide the hold
missing_input, round_expansion_refused, input_source_unavailableThe step had nothing to ask or its calls could not be authoredInspect the detail; author the repair
run_canceledA stop took the row before it started—

retry: { budget } on a model step bounds eligible node retries before the failure policy applies. It does not multiply the provider-attempt budget of a refused or exhausted route; neither manual retry nor a later profile edit renews that route. See Model selection and recovery. A failure's policy is propagate (skip not-yet-started descendants), absorb (settle in the failing write) or halt (hold for a person).

Run holds ​

Run statuses: pending | running | paused | needs_attention | canceling | completed | canceled. There is no failed: a reasoned cancel is the run failing.

A run at needs_attention names its reason — halt_failure, awaiting_human, deliverable_unresolved — and the task keys it is blocked on. A hold has no clock: it stands until a person decides. The deciding verbs are retry (run the failed task again under its own lineage, optionally on another model), abandon (settle the failure so the run moves past it) and compact (repair a round by authoring a summarizer). An applied append releases the hold back to running; if the rest still cannot resolve, the run re-holds. Explicit retry resumes only the failed node; completed tools and child requests stay completed. Regenerating the whole turn is a separate operation and not the recovery mechanism for preserving completed work.

Recovery procedures ​

Transient failures (rate limits, overload, timeouts): honor Retry-After, bound your attempts, and check the outcome before retrying a mutation — a failed turn may already have changed files or called external tools.

A disconnected stream confirms nothing. Reconnect, drain replay from your saved cursor, and read the turn or task over HTTP; see Events and streaming.

A refused input is blocked with blocked_reason. Edit or delete it rather than submitting duplicates.

An expired execution (410 execution_details_pruned) keeps its text and terminal state. New inputs still work with the retained history; regeneration of the expired candidate returns 409.

Credentials: a 401 is never explained. If a refresh rotation's outcome is uncertain, treat the connection as lost and start a new device authorization; never replay the old refresh token.

Nexus is licensed O’Saasy. The rest of the repository defaults to MIT.