How AI Agents WorkCourse map

Chapter 15 · Quality

Reliability

Agents fail in about a dozen familiar ways. Each has a cause, a sign in the record of a run, and a fix in your code.

Where failures start

Patch reports "Fixed, all tests pass", but it never ran the tests again. Nothing crashed, and no error was raised. This is the new kind of failure that agents bring. The model can be confidently wrong, and its mistakes look like normal answers.

Most failures start at one step of the loop. Knowing the step tells you where to look and where the fix belongs:

The thirteen failures, by where they start
Where it startsFailuresWhere the fix usually lives
The model decidesInfinite loops, repeated calls, hallucinated completionLimits, repeat checks, success checks
Building the context, saving stateDestroying state, forgetting constraints, too much context, too little context, wrong retrievalThe code that builds the context, summarizes it, and saves state
Your code actsTool errors, partial failure, duplicate actionsThe tool code, retries, and saved progress
Between agentsSubagent disagreement, cascading errorsChecks wherever one agent hands work to another

Failures also trigger each other. Too much context forces a summary, and the summary drops a rule. The agent then edits a file it was told to leave alone, and a retry repeats the damage. So look for the first failure in the record, not only the last.

Failures in the loop

Infinite loops

Why it happens
Patch's edit fails to apply, so it rereads the file and tries the same edit for 40 steps. Loops start when results stop changing the model's choices, when nothing defines "done", or when a needed result was cut.
How to spot it
Count the steps and the cost of every run. Flag runs that make no progress: no new file read, no new test result, and no change in state.
What to do
Set hard limits on steps, tokens, money, and time. When one runs out, stop with a report of how far the run got, or hand it to a person.

Repeated tool calls

Why it happens
Patch runs the tests five times in a row with no edit in between. The model has lost track of the result, because the output was cut short or fell out of the context.
How to spot it
Record each failing call with its arguments, the current version of the files, and the result. The same record twice means nothing changed between the attempts.
What to do
On the first repeat, remind the model: "This failed the same way at step 12." Stop after a few repeats without progress, and keep each call with its result when you shorten the context.

Hallucinated completion

Why it happens
Patch replies "Fixed, all tests pass", but its last edit failed and it never ran the tests again. Anthropic saw the same thing in long-running experiments, where agents declared the job done too early.
How to spot it
Compare the claim with evidence your code holds: the last test result, the files that really changed, or an API's response.
What to do
Check the success criteria in code whenever the model says it is done (chapter 1). Keep the agent away from the tests that grade it, or let a separate agent review the change.

Failures in state and context

Destroying useful state

Why it happens
Patch's history is replaced by a summary that drops the exact error message, and the original messages are deleted. Writes that overwrite records instead of adding to them lose state the same way.
How to spot it
Compare state before and after each write and each summary. Watch for facts the agent asks for again, and for files that suddenly shrink.
What to do
Keep the full history in storage and send the model a summary, as Deep Agents, Pi, and Hermes do (chapter 4). Keep checkpoints so you can roll back.

Forgetting constraints

Why it happens
At step 3, the user says "do not touch migrations", and at step 60, after a summary, Patch edits one. A rule given once gets buried under tool output, or the summary leaves it out.
How to spot it
Check each proposed action against a list of rules kept in code. Test that every rule survives your summaries.
What to do
Store the rules in your code's state, and add them to every context. Enforce the strict ones in the tool code, so writes to migrations/ are blocked whatever the context says.

Too much context

Why it happens
Patch reads twelve whole files and three test logs, and misses the one line that matters. In 2025, Chroma tested 18 models and found that performance "grows increasingly unreliable as input length grows".
How to spot it
Track the size of every context and what fills it. Watch for answers that ignore something in the logged context.
What to do
Cap tool output, read line ranges instead of whole files, and summarize near a limit (chapter 4).

Too little context

Why it happens
Patch is told "fix the login bug" and edits the front end, because the failing test never reached its context. The model filled the gap with a guess.
How to spot it
Look for generic answers, or mistakes that the missing file would have prevented. The logged context shows whether the fact was there.
What to do
Give the agent tools to search and read, and tell it to look before it acts. Always include the task, the rules, and the project instructions.

Wrong retrieval

Why it happens
Patch asks its memory about the database, reads that an old service "uses MySQL", and writes MySQL syntax for PostgreSQL. Search finds similar text, and similar is not always relevant or correct (chapter 5).
How to spot it
Log what each call retrieved, with its source and date. Test retrieval with questions whose answers you know.
What to do
Filter by project or service before ranking, and prefer trusted sources, such as config files.

Failures when acting

Tool errors

Why it happens
The test runner times out, the error escapes your tool code, and the run dies without a record. Tools fail often: timeouts, rate limits, missing files, and invalid arguments from the model.
How to spot it
Track errors for each tool and each kind of error. Look for runs that end in a crash instead of a stop rule.
What to do
Retry a timeout in code only for reads and for actions that are safe to repeat (chapter 12). Send other errors back to the model as tool results (chapter 2), and never let an error crash the loop.

Partial failure

Why it happens
Patch's nightly run prepares fixes for three of five issues, and then the process is killed. Two branches exist and one approval request went out, but nobody knows which issues are done.
How to spot it
Keep each item's status in your code's state, not only in the conversation. Look for tool calls without results.
What to do
Save a checkpoint after each step, so finished steps survive and only the unfinished step may run again (chapter 12). On resume, check the outside world before redoing anything, and report what is done and what is not.

Duplicate actions

Why it happens
After approval, Patch's request to open the pull request times out, and a blind retry opens a second one. A timeout means the outcome is unknown, not that the request failed.
How to spot it
Give every outside action an operation id, and alert when one id is attempted twice.
What to do
Resend only if the receiver ignores repeats of the same idempotency key and the key's retention window is still open. Otherwise mark it "outcome unknown" and confirm what happened first, because the first attempt may still be running (chapter 12).

Failures between agents

Subagent disagreement

Why it happens
One helper reports that tokens expire after 10 minutes, another reports 15, and the parent picks one. Helpers see different code, or read the same code differently, and each one sounds sure.
How to spot it
Compare results on shared facts before merging them. Require a source for each claim, such as a file and line.
What to do
Settle it with evidence: read the cited source, or run a check. Prefer the source of truth over the majority, and ask a person if the evidence cannot settle it.

Cascading errors

Why it happens
A helper reports that token expiry is checked in auth/tokens.py, an old copy that nothing calls, and Patch fixes that copy. The reviewer trusts the same claim, so nobody catches the mistake.
How to spot it
Trace each final claim back to its first source. Look for early results that nobody checked.
What to do
Check important facts at each hand-off, not only at the end. Prefer cheap checks in code, such as "is this function called anywhere?" and "does the failing test pass now?".

Why long runs fail: compounding

Imagine a task with 20 steps, where each step succeeds 95% of the time. The whole run succeeds only if all 20 steps do. This simple model assumes three things:

P(all 20 steps succeed) = 0.95 ** 20 = 0.36

So steps that each work 95% of the time give a run that works about a third of the time. A 50-step run works less than 8% of the time. Each assumption is wrong in practice, and changing each one teaches something.

Retries, when failures are independent

Suppose your code notices a failed step and retries it once. If failures are independent, a step now fails only when both tries fail:

per step, one retry  = 1 - 0.05 ** 2 = 0.9975
P(all 20 succeed)    = 0.9975 ** 20  = 0.95

One retry per step lifts the run from 36% to 95%. That is the case for noticing failures and retrying them.

Failures with a shared cause

Now suppose most failures share a cause, such as a misunderstood API or a wrong instruction. Say 4% of steps fail on every try, and another 1% fail at random. A retry fixes only the random ones:

per step, one retry  = 1 - 0.04 - 0.01 * 0.01 = 0.9599
P(all 20 succeed)    = 0.9599 ** 20           = 0.44

Now the retries lift the run only from 36% to 44%. Repeating an attempt cannot fix a mistake that happens every time. The agent needs a different attempt: new information, another approach, or a person.

Recovery, and steps that are not required

Real runs differ from the math in two more ways. Many steps are not required: a search that finds nothing is not fatal, because the agent can search again. Failures can also be repaired later. A test run at step 15 can catch a bad edit from step 9. A checkpoint lets a crashed run continue from its last saved step. The unfinished step may run again. Anthropic's multi-agent research system resumes from where an error happened, because "Agents are stateful and errors compound".

So the useful question is how soon your system notices a failure. Silent failures are the ones that compound. Put checks where errors start, and make each retry different from the last attempt. The same math explains why hand-offs between agents need checks (chapter 14).

Three defenses that cover most failures

Three moments from Patch's runs show the defenses at work. When an edit failed at step 14, the record showed the exact context, the call, and the error. When Patch kept failing in a loop, a step limit stopped it at 60. When it claimed success, a test run proved it wrong. These are a trace, a budget, and a verification gate.

Traces

A trace records everything a run did: each context, reply, tool call, result, and change of state, linked by ids. The entry for that failed edit might look like this:

{"run_id": "run_7f3", "step": 14, "kind": "tool_call",
 "call_id": "call_31", "tool": "edit_file", "args_hash": "a91c",
 "op_id": null, "context_tokens": 41200, "cost_usd": 0.021,
 "result": "error: old text not found", "ms": 180}

Log the exact context of every model call. Then you can tell whether a fact was in front of the model. Give every outside action an operation id, so duplicates show up.

Budgets

A budget is a limit your code enforces, so a failure stops at a known cost. Cap steps, tokens, money, time, and errors in a row, for each run and each helper. Decide in advance what happens at the limit: stop with a progress report, ask a person, or save and resume later. A run that often hits its budget has a problem that the budget only hides.

Verification gates

A verification gate is code that checks evidence before your system accepts a result. Tests are gates, and so is a check that a change touches only allowed files. Put gates where the model says it is done, at hand-offs, and before actions you cannot undo.

Run cheap checks in code first. Then use a model-based checker for things code cannot judge, and ask a person about what matters most. A model grading its own work is the weakest check. In Anthropic's experiments, "agents reliably skew positive when grading their own work", so a separate agent did the grading.

Running example: Patch gets reliability guards

Patch gets three guards. A repeat check warns the model when a call fails the same way on unchanged files. The fourth such failure stops the run. Budgets cap each run at 60 steps, $3, and 30 minutes, and "done" counts only when the tests pass. Each guard writes to the trace, so a stopped run says why it stopped.

+ key = (call.tool, call.args, workspace.version, hash(result))
+ n = failed_repeats.count(key) if result.failed else 0
+ if n == 2: warn_model("This failed the same way before, with the same files.")
+ if n >= 4: return stop("repeating without progress")
+ if run.steps >= 60 or run.usd >= 3.00 or run.seconds >= 1800:
+     return stop("budget", report=run.progress())
  if not reply.tool_calls:
-     return "success"
+     return "success" if tests_pass() and diff_ok() else push_back(check_output)

You decide, AI builds

Decide yourself

  • What counts as done, and which evidence proves it.
  • The budgets for each run and each helper, and what happens when one runs out.
  • Which outside actions need idempotency keys, and where the checks sit.

Delegate to AI

  • Trace logging and the trace format.
  • Repeat checks, budget counting, and timers.
  • Retry code with delays and limits.

Check yourself

What causes infinite loops, and what stops them? (Q27)

Answer

Loops start when results stop changing the model's choices, when nothing defines "done", or when tools keep failing the same way. Limits on steps and cost, repeat checks, clear success criteria, and handing the run to a person stop them.

Each step succeeds 95% of the time, and your code retries every failed step once. Why might a 20-step run still succeed less than half the time?

  1. Retries make each step slower
  2. Most failures share a cause, so a retry fails the same way
  3. Retries add steps, and more steps fail more often
Answer

Retries fix only random failures. If 4 of every 5 failures happen every time, one retry lifts the run from about 36% to only about 44%.

A run dies halfway through a batch of outside actions. How should it resume? (Q20)

Answer

Load the last checkpoint, and skip the steps recorded as confirmed. For a step with an unknown outcome, resend only with the same idempotency key while the receiver's retention window is open. Otherwise, find out what happened first. Then report what was done, what failed, and what never started.

Takeaways

Going deeper