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:
| Where it starts | Failures | Where the fix usually lives |
|---|---|---|
| The model decides | Infinite loops, repeated calls, hallucinated completion | Limits, repeat checks, success checks |
| Building the context, saving state | Destroying state, forgetting constraints, too much context, too little context, wrong retrieval | The code that builds the context, summarizes it, and saves state |
| Your code acts | Tool errors, partial failure, duplicate actions | The tool code, retries, and saved progress |
| Between agents | Subagent disagreement, cascading errors | Checks 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:
- Every one of the 20 steps is required.
- Each step succeeds with probability 0.95, independently of the others.
- There is no recovery: a failed step is never noticed, retried, or fixed.
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?
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
- The model's failures look like normal answers, so check its claims against evidence your code holds.
- Silent failures compound over long runs. Catch them early, and make each retry different from the last attempt.
- A timeout means "unknown", not "failed". Retry an outside action only when the receiver ignores repeats, and otherwise find out what happened first.
Going deeper
- Context Rot: How Increasing Input Tokens Impacts LLM Performance (Chroma, July 2025). Why long inputs hurt.
- Effective harnesses for long-running agents (Anthropic, November 2025). Agents that stop too early, and how to prevent it.
- Context Engineering for AI Agents: Lessons from Building Manus (Manus, July 2025). Keep failed actions in the context, and make every summary reversible.