On this page · 8 sections
  1. Decide what each operation does when it fails
  2. Shape the failure as data
  3. Verify before you retry
  4. Give partial completion a shape of its own
  5. Escalate on a named condition
  6. Test the recovery path before you rely on it
  7. A recovery checklist
  8. Frequently asked questions

Error handling for AI agents usually starts life as a copy of error handling for people. A call fails, a message comes back, and somewhere a human reads it and works out what to do. An agent does not read it that way. It receives a string, has to infer from that string whether the world changed, and then chooses between trying again, trying something else, asking a person, or reporting success it cannot justify. Almost every bad outcome in that list comes from the same gap: the error described the past and said nothing useful about the next move.

Decide what each operation does when it fails

Work operation by operation rather than endpoint by endpoint. For each one, write down three answers before writing any handling code.

Can this leave partial state behind? A single-row update usually cannot. A batch import, a multi-leg booking, or anything that writes to two systems usually can.

Is repeating it safe? RFC 9110 defines an idempotent method as one where the intended effect on the server of multiple identical requests is the same as for a single request, and a retry silently assumes that property every time it fires.

Who resolves it if the agent cannot? Sometimes nobody has to, because a narrower scope or a different capability is available. Sometimes it is a named role, and then the escalation path needs as much design as the happy path.

Three answers per operation is not much work, and it gives you the table the rest of the recovery design reads from.

Shape the failure as data

The MCP tools specification asks that tool execution errors provide actionable feedback a model can use to self-correct, and it keeps protocol-level errors distinct from errors inside a tool result so that a failed operation is still a structured result rather than a broken exchange. On the HTTP side, RFC 9457 defines a machine-readable problem details format so that an API can carry the specifics of a failure without inventing a new response shape for every endpoint.

Both treat a failure as structured data.

Here is a generic error payload of the kind most services return today:

{
  "error": "Internal error",
  "code": 500
}

An agent receiving that can do one of two things: retry blindly, or stop. Neither choice is informed. The same failure, shaped for recovery:

{
  "error": {
    "what_failed": "reserve_inventory",
    "reason": "downstream_warehouse_unavailable",
    "state_changed": false,
    "retry_safe": true,
    "retry_after_seconds": 30,
    "correlation_key": "res-2026-09-19-k41",
    "fix": null,
    "escalate_to": null
  }
}

The example is written for this guide and matches no particular product. Four of its fields do most of the work.

Field What it lets the agent do
what_failed Attribute the failure to a step rather than to the whole run
state_changed Choose between resuming and restarting without guessing
retry_safe Repeat the call, or refuse to repeat it, on evidence
fix Ask for exactly the missing input instead of asking an open question

fix is the field that turns a dead end into a request for something specific. When the missing piece is an input, the MCP tools specification supports multi-round-trip flows so a tool can request more information mid-task rather than failing outright. When the missing piece is authority, the step-up authentication challenge described in RFC 9470 gives a resource server a standard way to say that the caller must reach a higher authentication level before the request is accepted. In both cases the workflow continues from where it paused.

Two fields need care. retry_after_seconds should reflect what the service actually knows. HTTP already has Retry-After for this, and a fabricated number is worse than an absent one. state_changed: false is a claim the service is making about itself, so it is only as trustworthy as the service. When the failure is a client-side timeout, no service said anything at all.

Verify before you retry

A timeout is the hardest case in agent error recovery because it looks like a failure and may be a success. The client never received a result. The operation may have completed anyway.

The rule here is to check state before repeating a side effect. Generate a correlation key at submission time, expose a status lookup that accepts that key, and make the agent resolve uncertainty through the lookup rather than through a second submission. The worked example at Timeout recovery: verify before retry walks a synthetic sync job through that sequence: the first submit times out, the status lookup finds the operation already accepted under the same idempotency key, and the correct next action is to observe the existing operation rather than start a new one.

When no status lookup exists, the honest classification is uncertain, and uncertain work should go to a person rather than into another attempt. Verify before retry is one of five recovery patterns, alongside idempotency keys, errors that name the next step, truthful exit codes and refusals that name the missing permission, collected with public examples in Approval, handoff and recovery patterns for AI agents.

Each attempt should also carry new information. If nothing about the call or the world has changed since the last one, there is no reason the next attempt would go differently, so the scheduler may as well stop and ask. Record agent retries as product history covers what to record per attempt and why the distinction between a repetition and a recovery belongs in the data model.

Give partial completion a shape of its own

Batch work fails in the middle. A run that processed 40 of 60 records and returns a single error has thrown away the only thing the next actor needed to know.

Report the boundary instead: which units completed, which failed and why, which were never attempted, and whether the completed ones can be reversed. That record is what makes a resume possible, and resuming from a known boundary is cheaper and safer than rerunning from zero. Benchmark designers working on long-horizon computer use have put the same idea at the centre of their task design. The OSWorld 2.0 repository describes its workflows as stressing hidden state and stateful recovery: resuming correctly is a hard problem of its own.

The partial-completion record is also a handoff, and it needs the same fields as any other. An agent context handoff should carry the reason for the work sets out that record.

Escalate on a named condition

Escalation triggered by a retry counter arrives too late and too often at once. A named condition can trigger it while a person can still help.

Useful conditions to encode: the operation is irreversible and the agent lacks the scope; the input is ambiguous in a way that changes the outcome; the same failure class has appeared twice in one run; the run has ingested untrusted content and is now about to take a consequential action. That last one comes from the security literature rather than from reliability practice. Beurer-Kellner et al. (2025) argue that secure agent designs should constrain the set of consequential actions available after untrusted input has been ingested, which makes “untrusted content, then a side effect” a sensible place to require a human.

An escalation should hand the person a decision to make. Name the blocked action, the missing scope or input, the state already committed, and the options with their consequences. Human approval workflows for AI agents covers how to design that moment so the person is agreeing to something they can actually evaluate.

The path back after a failed callAfter a failed call the agent reads what failed and whether state changed, checks status by its correlation key when the state is unknown, and retries or resumes only when that is safe; otherwise it asks for the missing input or authority, and a named condition escalates to a person.NOYESA call failsRead the failurewhat failed, what changedCheck status by keywhen the state is unknownSafe to retry?Retry or resumeon evidenceResume from the pauseAsk for the inputor the authorityEscalateon a named condition
Agent error recovery as a designed path, with the branches for timeouts, missing input and escalation. Open the diagram

Test the recovery path before you rely on it

Public evaluation practice has a name for testing recovery paths before you need them: fault injection. ReliabilityBench (2026) varies task perturbations and injected tool and API failures and reports a reliability surface rather than a single score, on the reasoning that behaviour under failure is its own property and not a corollary of behaviour under success.

You do not need the formalism to borrow the method. Take your three most consequential operations, simulate a timeout, a rate limit, a partial response and a schema change against each, and watch what the agent does. Evaluate the decisions in an agent workflow covers how to score what you see.

A recovery checklist

  1. Every operation is classified as reversible, partially reversible, or irreversible.
  2. Every failure response names the step that failed, not just the run.
  3. state_changed is present and honest, including the case where the service cannot know.
  4. Retry safety is a property of the operation, recorded once, not a per-caller guess.
  5. A correlation key exists for anything with a side effect, and a status lookup accepts it.
  6. Partial completion has a record shape that supports resuming from the boundary.
  7. Escalation fires on named conditions and hands over a decision with options.
  8. At least one fault injection test exercises each recovery path you claim to have.

Start with item five. A missing correlation key is what turns an ordinary timeout into a duplicated side effect, and it is usually the cheapest of the eight to add.

Frequently asked questions

What is agent error recovery? Agent error recovery is the designed route a workflow takes after a step fails, rather than the exception handling bolted on afterwards. It covers what the failing call tells the agent, whether the operation left state behind, whether another attempt is safe, and who takes over if it is not. Designing it means deciding those answers in advance for each operation instead of leaving them to be inferred from an error string.

What should an error response tell an AI agent? Four things: what failed, whether state changed, whether a retry is safe, and what input or authority would make the next attempt succeed. The MCP tools specification makes the same point from the protocol side, asking that tool execution errors give actionable feedback a model can use to self-correct. An error that only carries a message and a code forces the agent to guess at all four.

When is it safe for an agent to retry a failed call? When the operation is idempotent, or when the agent has verified the current state first. RFC 9110 defines an idempotent method as one whose intended effect is the same for multiple identical requests as for a single one, which is exactly the property a retry depends on. For anything else, a timeout is not evidence that nothing happened, so the agent should check status by a correlation key before repeating a side effect.

How should an agent handle a partially completed task? Report the boundary rather than the outcome. The record should say which units completed, which failed, which were never attempted, and whether the completed ones are reversible. A run that processed 40 of 60 records and returns a single failure is worse than useless, because the next actor cannot tell whether rerunning it will duplicate the first 40.

A workflow that pauses well is easier to trust than one that never admits it stopped.