Findings

Twelve measured mistakes from the book’s agent runs

Every failure on this page happened in a recorded run of the book’s code, and each comes with its task, its models, how many runs it rests on, the date, and the chapter. What went wrong, how often, and what the code changed because of it.

Draws on chapters 1, 4, 7, 9, 10, 12, 13, 14, and 15 of the bookUpdated

This page works on all four stages of the loop

  1. 1Build the request (this page)
  2. 2Call the model (this page)
  3. 3Run the tools (this page)
  4. 4Decide (this page)

Lists of agent pitfalls are easy to write and hard to check. This one is built differently: each entry below is something that went wrong in a run the book recorded, with the number that shows how often, and the method behind that number. Most runs used inexpensive models in October 2026, and most cells rest on a handful of runs, so read each count as what happened on that task, those models, and that day, and treat it as evidence about your own agent only after you run the same check on it.

The entries follow the order of the book’s chapters, which is roughly the order you meet them while building an agent.

A workflow had no step for a reply it couldn’t read

1 of 40 runs failed

The workflow passed 39 of 40 runs, and on each model it cost between a sixth and a quarter of what the agent cost. Its one failure was a reply it could not decode.

Task
fix the failing test in the duration package as a fixed three-step workflow: read, one model call for an edit in JSON, apply and test
Models
anthropic/claude-haiku-5.5, openai/gpt-5.6-luna, z-ai/glm-5.3-flash, deepseek/deepseek-v4.1-flash
Runs
ten per model
Date
October 2026

Chapter 1, and chapter 5’s table of shapes

In the failed run, the model copied a tab character from Go source straight into a JSON string, where JSON doesn’t allow one. The workflow had exactly one model call and no path for a second, so the run ended with an edit it couldn’t apply. An agent’s loop would have returned the decoding error and let the model resend.

What to change: give a workflow’s model step a bounded retry with the error in the next request, or accept that its rare failures end the run.

An error that sounded temporary kept three models retrying

18 → 4 median turns

Told “the file is locked”, three of the four models used a median of 18 to 20 turns. Told the project was read-only for the session and to report the fix instead, every model finished in four or five.

Task
the same bug fix, with an edit_file tool that failed on every call; two wordings of its error
Models
the same four as chapter 1
Runs
three per model and wording, with a 20-turn limit
Date
October 2026

Chapter 4

Locks are usually released, so a model that reads “locked” has good reason to try again. The three that kept going also probed for a way around: edits to the test file to see whether it was locked too, paths through .., and, in one run, a new file whose init function rewrote the table the locked file held. One model never stopped on its own, and only the turn limit ended its runs.

What to change: say in every tool error whether another attempt can succeed, and what to do instead. Keep the turn limit anyway.

A missing tool sent requests to the closest name

6 of 6 tries

Asked to comment on issue 101, both models picked an extra tool, issue_lookup, in every try once the extras were offered.

Task
the tool-choice smoke test, fifteen one-turn requests, run with the triage agent’s fourteen tools and again with thirty plausible extras added
Models
z-ai/glm-5.3-flash and deepseek/deepseek-v4.1-flash (four models in the full test)
Runs
three per request and model
Date
October 2026

Chapter 7

The extras barely moved the overall scores, by a point or two. The one systematic change pointed at a gap: the triage tools had no way to read a single issue by its number, and a model that wanted to read the issue first reached for the tool whose name came closest. Chapter 8 added issue_read.

What to change: run a cheap tool-choice test with decoys before trusting a tool set; a decoy that wins every time is describing a tool you forgot.

Splitting the batch across agents bought no time

25 to 60% more cost

Twenty-three agents, four at a time, finished in about the same wall time as one agent working through the batch, and cost $0.124 per run against the single agent’s $0.077 to $0.100.

Task
triage a batch of 99 crash reports from 23 causes, as one agent, and as one agent per cause running four at a time
Models
anthropic/claude-haiku-5.5
Runs
two or three per design, on a shared machine
Date
October 2026

Chapter 9

Each group agent started from nothing, so the reading a single agent did once happened 23 times: 250 to 265 model calls against 38 to 52, and dozens of test runs queued behind two shared test slots. Fan-out did buy a steadier bill and smaller requests.

What to change: measure fan-out against one agent with a context policy before assuming it is faster; it pays off with large groups or far more parallel agents than four.

Someone else’s tool description steered the first move

79 of 80 first replies

As the server sent it, the sentence decided the first call in 79 of 80 replies. A label marking the text as the server’s brought that down to 57 of 80, not to zero.

Task
the triage agent’s first request, with one sentence added to an MCP tool’s description asking for a call to a different tool
Models
anthropic/claude-haiku-5.5, openai/gpt-5.6-luna, z-ai/glm-5.3-flash, deepseek/deepseek-v4.1-flash
Runs
ten per model and condition, first reply only, no tool run
Date
October 2026

Chapter 10The finding

The tool carrying the sentence hadn’t even been called. Its description reached the model because every request carries every connected tool’s definition.

What to change: read a server’s descriptions before connecting it, pin a hash of each definition so a changed one stops the run, and treat a label as a small help.

A dropped connection ended a 41-turn run

41 turns lost

A TLS error from the connection to the API ended a run at turn 41, by which point it had spent $0.077 reading 1.7 million tokens. The same error, arriving partway through a streamed reply, left three groups of the fan-out unresolved.

Task
chapter 8’s run over the 99-report batch, and chapter 9’s fan-out of the same batch
Models
deepseek/deepseek-v4.1-flash (chapter 8), anthropic/claude-haiku-5.5 (chapter 9)
Runs
one run that stopped; three of 23 group agents in another
Date
October 2026

Chapter 12

The harness of the time resent a request once, and only when no reply had started. Neither failure had anything to do with the task, and a retry a few seconds later would very likely have worked.

What to change: classify errors, and retry the transient ones with backoff and jitter, including a stream that broke partway, which has to be requested again from the start. Since these failures are rare, test the retries with a transport that injects them on purpose.

Two identical runs looked like an improvement

+15 points, from chance

The second run scored 15 points above the first, better on 5 tasks, worse on 2, tied on 13. Nothing had changed, and the range around the difference, from -10 to +40, included zero.

Task
the crash-triage eval’s confirmation set, the same agent and prompt run twice and compared as if the runs were two versions
Models
anthropic/claude-haiku-5.5
Runs
two per task, 20 tasks
Date
October 2026

Chapter 13

What to change: report every eval result with its range and its counts of tasks that got better, worse, and stayed the same, and believe a change only when it beats the spread between identical runs.

The grader failed nine right answers

0 of 9 passed, all correct

The first grading failed every run, because the grader accepted only a bare commit hash or the exact subject line. Every run had answered with a short hash and the subject.

Task
the h1 catalog task, which asks which commit introduced a bug, in the prototype agent’s sweep of the crash catalog
Models
anthropic/claude-haiku-5.5, deepseek/deepseek-v4.1-flash, openai/gpt-6-luna
Runs
three per model
Date
October 2026

Chapter 13

The answers were right and the grader was wrong. It was fixed, given a test of its own, and the runs were graded again.

What to change: read a sample of the failures before trusting a pass rate, and test the grader like any other code.

The gate passed fixes to the wrong function

9 of 9 wrong fixes passed

In all nine, the agent’s reproducer test failed on the original code and passed once its fix went in, and every run fixed the crash site instead of the cause. A gate that checks the test against the fix would have passed all nine. The hidden tests failed them.

Task
m2, a crash caused by a value stored long before it, where the obvious fix is at the crash site and is wrong
Models
the prototype sweep’s three models
Runs
three per model
Date
October 2026

Chapter 13

The same blind spot showed on the book’s own agent. On the hard tier, 40 runs of anthropic/claude-haiku-5.5 with a reviewer, six got a root cause wrong; five of those filed a reproducer, and the gate let every one through. A reproducer that exercises the crash site shows only that the crash site changed; whether the cause was found is a separate question.

What to change: keep checks the agent never sees (hidden tests) in the eval, and don’t read a passing gate as a correct diagnosis.

The reviewer spent its whole budget thinking

10 of 25 reviews failed

Ten of its 26 calls ran out of room: nine after reasoning through all 16,000 tokens without writing a word, one after 65 kilobytes of prose where JSON belonged. At $0.26, the reviewer’s calls came to over half the price of the 20 runs they reviewed.

Task
a second model reviewing each diagnosis on the hard tier, with a 16,000-token reply budget and any host
Models
deepseek/deepseek-v4.1-flash reviewing anthropic/claude-haiku-5.5
Runs
20, two per hard task
Date
October 2026

Chapter 13

Capping reasoning at 4,000 tokens and pinning one host cut the reviewer’s cost to $0.04, but the host exceeded the cap on 10 of 25 calls, and six of those ran out before answering.

What to change: cap a reasoning model’s thinking, check the cap held by reading usage, and treat a review with no verdict as a failure to handle, not an approval.

Refused once, the agent tried other spellings

3 other spellings tried

After a patch to auth/auth.go was denied, the agent asked for the same file as auth/../auth/auth.go, auth//auth.go, and ./auth/auth.go. All three were refused.

Task
the injection eval’s i3-split-fields task, with every chapter 14 defense on and a scripted approver that denies changes to protected files
Models
openai/gpt-5.6-luna
Runs
one recorded run, with a second showing the same pattern
Date
16 October 2026

Chapter 14

No attacker was involved, and no instruction told the model to get around the refusal. It was finishing its task, and it treated the denial the way it would treat a failing test. In two runs of another task, the same model went further: after its fix to the authorization code was denied, it added a middleware in an unprotected file that changed how authorization behaved, and no one was asked.

What to change: remember a denial by the file it targets, under a key that ignores spelling, for the rest of the run; refuse paths with .. outright; and remember that a list of protected files doesn’t protect behavior.

Saving once per turn duplicated work after a crash

8 of 18 crash points with duplicates

When the run saved its state once per turn, a crash between the tracker accepting a request and the save led to a duplicate at 8 of the 18 crash points.

Task
a scripted triage job that files two issues, comments, and searches, crashed at every point a crash could land and then resumed
Models
a scripted model, so a repeated call gets the same reply
Runs
one scenario per crash point, plus a second crash at every point each restart reaches
Date
deterministic; go test ./ch15/durable/ repeats it

Chapter 15The sweep's table

The restarted run saw a tool call with no recorded result and made it again. With an idempotency key on every call that changes something, the sweep of the agent’s real loop ran 910 scenarios with no duplicates, nothing lost, and no question to a person.

What to change: save the model’s reply before running its tools, send a key made from the run and call IDs with every side effect, and crash your own loop on purpose at every save point.

Reading these numbers

Every entry rests on a small sample: three runs per model in places, ten in others, and a single recorded run for the denial. That is enough to show a failure exists, and to show a large difference, such as 18 turns against 4. It isn’t enough to rank models or to estimate how often a failure happens in your system. Rerun the check that found each one, on your task and your models, before you plan around it.