· 6 min read ·

When Tool Calls Fail: Error Recovery Inside the Coding Agent Loop

Source: simonwillison

Every coding agent is a loop. The model produces a tool call, the environment executes it, the result returns as new context, and the model decides what to do next. Simon Willison’s guide on how coding agents work describes this pattern clearly. What’s less obvious is what happens when steps in that loop fail, because error handling in agent systems is both their most underappreciated capability and the source of some of their most confusing behavior.

Errors Are Just Tool Results

In traditional scripting, errors divert or terminate execution. A bash script hits a command that exits non-zero and stops, unless you’ve written explicit traps or conditionals. The script doesn’t interpret the error; it follows whatever control flow you specified at write time.

In the agent loop, there’s no separate control flow for errors. A failed tool call produces a tool_result message containing the error output, and that message enters the context window like any other result. The model reads it at the next inference call and decides what to do.

In the Anthropic Messages API, a failed tool result looks like this:

{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "tu_01",
      "is_error": true,
      "content": "FileNotFoundError: src/auth/token.py does not exist"
    }
  ]
}

The model receives this as part of the messages array on the next API call and reasons about it from context. It might infer the path was wrong and search for the correct one. It might read the directory structure to understand what actually exists. It might decide the error is unrecoverable and report back to the user. Which of these happens depends on the model’s training, the system prompt’s instructions, and what’s already accumulated in context.

This is qualitatively different from error handling in compiled languages, where the compiler enforces error propagation rules. The model’s response to a failed tool call is a runtime inference decision, not a static guarantee.

Why This Enables Genuine Resilience

The loop-as-error-handler pattern lets agents recover from mistakes that would terminate a script entirely.

Consider a common scenario: the model reads a file, plans an edit, then submits that edit with expected surrounding context that no longer matches because an earlier tool call modified the file. The edit fails. A script stops. The agent reads the mismatch error, re-reads the file to get the current state, and retries against the actual content. The correction happens automatically because the failure description carries enough information to diagnose and fix the immediate problem.

The ReAct paper (Yao et al., 2022) formalized this pattern of interleaving reasoning and acting. Their experiments showed that models given the ability to observe results and adjust consistently outperform models that plan everything upfront, particularly when environment state is uncertain. Coding tasks are exactly this kind of problem: the state of a real codebase is not predictable from a description alone.

A concrete version plays out whenever an agent runs tests after editing code. The test output enters context as a tool result: test names, failure messages, stack traces. The model doesn’t need special test-awareness; it reads failure output as text and draws inferences from it. An agent that introduced a regression two steps earlier frequently catches and fixes it from the test output alone, because the failure directly names the function and the assertion that failed. This is different from static analysis, which runs before the change and flags potential issues. The agent loop gets the benefit of runtime feedback: actual behavior, not predicted behavior.

The Failure Modes

The same property that enables recovery also enables pathological loops.

The most common failure is infinite retry. The model encounters an error, tries a corrective action, hits the same error, tries the same correction, and continues. Without a loop counter or escalation policy in the system prompt, nothing stops this from consuming the entire context budget. A well-designed agent system bounds retries at the orchestration layer or instructs the model explicitly to escalate after N failed attempts of the same type.

A subtler failure is error normalization. When the model is deep into a long task with many accumulated tool results, it may begin treating persistent errors as background noise rather than signals to investigate. The error is present in the context, but the model’s attention is elsewhere, and subsequent tool calls proceed as if the error hadn’t occurred. This looks, from the outside, like the agent is ignoring an obvious problem, which is essentially what’s happening. The “lost in the middle” phenomenon (Liu et al., 2023) documented how model retrieval accuracy degrades for information positioned in the middle of long contexts, and errors that accumulate early in a long run are precisely the content most at risk of being underweighted.

A third failure mode is divergent state. If an agent partially completes a multi-step transformation, hits an unrecoverable error, then starts a different approach, it may end up with code that reflects both the partial first attempt and the second attempt in inconsistent ways. The context contains both paths, but the model doesn’t necessarily carry a reliable accounting of which changes are in effect. Code that looks syntactically valid may be semantically incoherent because two different strategies were layered on top of each other.

What System Prompts Do About This

The instructions in a coding agent’s system prompt are partly about capabilities and partly about failure hygiene.

Claude Code’s approach includes instructions to read files before editing them, to verify changes after making them, and to stop and report to the user when something unexpected blocks progress. Reading before editing reduces the chance of an edit mismatch. Verifying after editing catches cases where the edit succeeded textually but broke something downstream. Escalating to the user breaks retry loops before they exhaust the context window.

The minimal footprint principle common to well-designed coding agents serves a related function. Preferring reversible, targeted actions means that when the agent does enter a bad state, the damage is bounded. An agent that prefers precise file edits over wholesale rewrites leaves a codebase where errors are localized. One that requires a clean git state before starting can always be reset to the last known-good point. Reversibility is a prerequisite for safe error recovery.

Some systems add an explicit reflection step: before continuing past a certain number of tool calls, the model summarizes what it has learned and what it intends to do next. These summaries compress the context and create a structured opportunity to surface incorrect assumptions before they propagate further.

Designing for Error Observability

For developers building on top of coding agent frameworks rather than just using them, error paths deserve as much design attention as success paths.

Tool implementations should return structured diagnostic information, not just exception messages. A FileNotFoundError with a bare path gives the model less to work with than one that includes the directory that was searched, the closest matching file found, and a suggested correction. The model will use whatever diagnostic signal is available in context; richer error output directly improves recovery quality.

Tool descriptions in the function definition schema should document what error outputs look like, not just what successful outputs look like. If the model has seen examples of error responses during context setup, it has a prior on what failure states mean and what corrections are appropriate.

Finally, logging the full tool call sequence separately from the final output is essential for debugging. When an agent produces a wrong result, the root cause is almost always a failed tool call followed by incorrect recovery, not the final action itself. Without a record of the intermediate sequence, that diagnostic chain is invisible. The context window is ephemeral; the tool call log is the audit trail.

The loop structure that makes coding agents capable of genuine multi-step reasoning is the same structure that makes their failures compound in non-obvious ways. Error recovery is not a secondary concern in agent design; it is the primary mechanism by which agents handle the gap between their initial model of a codebase and the codebase as it actually is.

Was this interesting?