Exception handling that makes agents safe to leave alone
Autonomous agents fail in ways code never did — ambiguous inputs, half-applied side effects, low-confidence decisions. We engineer the failure paths first: typed exceptions, retry and compensation policies, clean escalation, and dead-letter queues that turn every edge case into an auditable event.
- Typed exception taxonomy
- Retry, compensate, or escalate
- Dead-letter queues with full context
- Human escalation that closes the loop
An agent's failure modes are not your code's failure modes
Deterministic software fails predictably; you catch a thrown error and roll back. An agent fails probabilistically — it can misread a field, pick the wrong tool, or be quietly half-right.
A traditional try/catch assumes the failure is the exception. With agents, the dangerous case is the one that never throws: the model confidently completes a task using the wrong assumption, and your systems happily record the result. There's no stack trace for being wrong.
So exception handling for agents is really three problems stacked together. First, detection — knowing the agent is off-track when it doesn't error. Second, classification — deciding whether a given failure is retryable, compensable, or out of scope. Third, disposition — routing it to a retry, a compensation handler, a human, or a dead-letter queue, with enough context to act. Get this layer right and autonomy becomes a question of trust budget rather than a leap of faith.
Five mechanisms, one safety net
Each agent action passes through a governed handler that decides what happens when reality doesn't match the plan.
Typed exception taxonomy
We classify failures — transient, validation, policy, low-confidence, irreversible — so the agent reacts by type instead of guessing. Classification drives every downstream decision.
Retry with backoff & idempotency
Transient, idempotent failures retry with bounded backoff and a budget. We never retry a side-effecting call that isn't safe to repeat.
Compensation & sagas
When a multi-step workflow fails midway, compensation handlers complete or reverse partial work so state never ends up half-applied.
Escalation to humans
Out-of-policy, ambiguous, or low-confidence cases route to a person with the full decision context attached, not a cryptic alert.
Dead-letter queues
Anything the agent can't resolve lands in a DLQ — captured, never dropped — ready to replay, repair, or close.
Circuit breakers
When error rates spike or a downstream dependency degrades, the agent trips a breaker and pauses rather than amplifying a bad state.
What happens when an action fails
A single, predictable flow every agent action runs through — no improvisation at the edge.
Detect
Output validators, confidence scores, and invariants flag the failure — including the ones that don't throw an error.
Classify
The handler tags the failure by type: transient, validation, policy boundary, low-confidence, or irreversible.
Route
Retry the transient ones, compensate the partial work, escalate the ambiguous ones, or trip a breaker on systemic faults.
Record
Every disposition writes to the DLQ and the decision lineage, so the next version learns from the edge case.
Fail loud, or fail autonomous?
There's a real tension here. Escalate too eagerly and you've built an expensive notification system that wakes people up for noise — the agent never earns its autonomy. Retry and self-heal too aggressively and the agent papers over genuine problems, compounding bad state until someone notices the damage downstream.
We tune that boundary deliberately, per workflow, using the same risk thresholds that gate execution. Low-stakes, reversible steps get a wide self-healing budget. Irreversible or high-cost steps fail loud and escalate early. The taxonomy is what lets you set this dial precisely instead of choosing one blunt policy for the whole system.
- Per-workflow retry and escalation budgets
- Risk thresholds drive the self-heal vs. escalate dial
- Abstention treated as a valid, cheap outcome
Naive try/catch vs. agent exception handling
Why bolting traditional error handling onto an agent leaves the dangerous failures uncovered.
| Wrapping the agent in try/catch | A governed failure-handling layer | |
|---|---|---|
| Detects | Only failures that throw | Throws plus low-confidence and silent-wrong outputs |
| Retry logic | Blind retry until budget runs out | Retries only transient, idempotent failures |
| Partial work | Left half-applied | Completed or reversed via compensation |
| Unresolved cases | Logged and lost | Dead-lettered with replayable context |
| Human handoff | A vague alert | Escalation with full decision lineage |
| Learning | None | Edge cases feed the next version's guardrails |
Frequently asked questions
What's the difference between a retry and an escalation?
A retry is appropriate when the failure is transient and idempotent — a timeout, a rate limit, a 503. An escalation is for failures the agent can't or shouldn't resolve alone: ambiguous data, a policy boundary, or anything that crosses a risk threshold. The hard engineering work is classifying which is which at runtime, not retrying blindly until you exhaust a budget.
Where do failed actions go when the agent gives up?
Into a dead-letter queue with the full context attached — inputs, the plan, every tool call, the model's reasoning, and the exception type. Nothing silently disappears. A human or a triage agent can replay, repair, or close the item, and the resolution feeds back into the next version's guardrails.
How do you keep a half-finished workflow from corrupting state?
We design side-effecting steps to be idempotent or compensable. If an agent books a vendor but fails to record it, a compensation handler either completes or reverses the partial work — the same saga pattern distributed systems use. Approval gates sit in front of the irreversible steps so a human signs off before the point of no return.
Can the agent decide to stop on its own?
Yes, and it should. We give agents explicit 'I'm not confident' and 'this is out of policy' exits so abstention is a first-class outcome, not a fallback after three bad attempts. An agent that halts cleanly and escalates is far cheaper than one that confidently completes the wrong work.
Related architecture decisions
Exception handling is one layer of a governed agent stack. Explore the rest.
Bring the workflow that scares you. We'll map its failure paths.
One working session to chart where your agent can fail, what's reversible, and where a human needs to stand in the loop.