Errors & Retries

Preview

Typed failures, retry policy, idempotency and escalation.

Errors are classified so the runtime can respond correctly. A rate limit is not a bug, a 404 is not a network failure, and a permission denial should never be retried.

Error taxonomy#

TypeRetryableRuntime response
timeoutYesExponential backoff, up to the step retry limit
rate_limitedYesRespect retry_after, then backoff
upstream_5xxYesBackoff with jitter
networkYesImmediate retry once, then backoff
invalid_argumentsConditionallyRe-synthesize arguments with the validation error attached
not_foundNoTreated as a result; the planner adapts
permission_deniedNoEscalate or replan; never retried
precondition_failedNoReplan — the world differs from the plan assumption
upstream_4xxNoSurface to the planner with the payload
internalYes (once)Retry, then fail the step with a trace reference

Idempotency#

Every effectful call carries an idempotency key derived from the run, step and argument hash. Retries reuse the key so a duplicate dispatch cannot duplicate the effect — provided the tool honours it.

ts
defineTool({
  name: class="tok-str">"billing.refund",
  effectClass: class="tok-str">"financial",
  idempotency: class="tok-str">"required",     // runtime refuses to retry without support
  async execute(args, ctx) {
    return ctx.http.post(class="tok-str">"/refunds", {
      body: args,
      headers: { class="tok-str">"Idempotency-Key": ctx.idempotencyKey }
    });
  }
});

Escalation ladder#

  1. 1Retry within the step, up to the step retry budget.
  2. 2Try an alternative tool with the same capability.
  3. 3Replan the step with a different approach.
  4. 4Reduce scope and report the reduction.
  5. 5Request human input.
  6. 6Fail the task with a precise reason and the partial results produced so far.

Last updated 2026-09-02