Three ways a run ends

An agent run has three outcomes, not two. It finishes the job. It fails loudly. Or it stops, reports success, and hands you work it did not actually do. Most of the engineering effort in production agents goes into the third case, because nothing in the logs marks it as a failure and nothing in the transcript reads as wrong.

Cheap to notice Expensive to notice
Ends 1

It finishes

The goal is met, the artifacts exist, and the summary matches what happened. The case every demo shows.

Ends 2

It fails loudly

An exception, a budget exhausted, an iteration cap hit. Annoying, but honest - the system tells you it did not work.

Ends 3

It claims success

Eight of ten things done, no errors raised, a confident summary. You find out days later, from a customer.

Before any specific failure mode, it is worth being clear about why long runs are fragile in principle. Take a step that succeeds 95% of the time - excellent by the standards of anything a language model does unaided. Twenty of those in sequence succeed about 36% of the time, because 0.9520 is 0.36. Push per-step reliability to 99% and a fifty-step run still only completes cleanly about 60% of the time.

Nothing is broken in that arithmetic. It is just what independent probabilities do. The practical consequence is that agent reliability is not primarily a model problem, it is a length problem - and every pattern in this article is an attempt to interfere with that multiplication. Fewer steps. Checkpoints that stop an error propagating. Verification that catches a bad step before the next one is built on top of it.

Reliability per step is a model property. Reliability per run is a design property.- the distinction most agent postmortems come down to

The loop that will not stop

The most visible failure, and the least damaging. An agent that cannot make progress keeps trying variations of the same broken approach until something external stops it: the iteration cap, the token budget, or an engineer watching the cost graph.

The mechanism is worth understanding precisely, because the obvious fix does not work. The model is not stubborn. On each pass it sees a transcript, and unless that transcript makes the pattern of failure legible, each retry looks like a fresh reasonable attempt. Four slightly different failed calls to the same endpoint do not read as "this endpoint is not going to work" - they read as four data points, each of which suggests one more thing to try. Telling the model to avoid repeating itself in the system prompt does very little; it cannot see the repetition.

What actually helps:

  • Hard budgets, enforced by the runtime. Iteration count, wall-clock time, and money. Not guidance in the prompt - a limit in the harness that the model cannot talk its way past.
  • Repetition detection. Hash the tool name plus its arguments. Three near-identical calls in a row is not a plan, it is a stall, and the runtime can say so.
  • Force a plan revision, not another attempt. After k failures, stop letting the model pick the next action and make it explain why the current approach is not working first. Changing the shape of the next turn breaks the pattern in a way that instructions do not.
  • Make failure legible. A raw stack trace is close to noise. A short structured error the model can reason about - what was attempted, what came back, whether it is retryable - changes the decision it makes next.

Context exhaustion

Every observation an agent reads stays in the transcript, and tool output is almost always the largest consumer. A directory listing, a query result, a page of documentation - each is cheap once and ruinous forty times. Long runs do not usually die of context exhaustion; they degrade toward it, which is harder to spot.

The degradation has a characteristic shape. The agent stops referring to the original goal. Constraints given in the first message - the deadline, the tone, the folder it is allowed to touch - quietly stop being honoured. It is not that the model has decided to ignore them; they are simply far away now, buried under sixty tool results, competing with far more recent material.

Three responses, in ascending order of effectiveness:

  • Summarise and drop. Compress older turns as the window fills. Standard, necessary, and lossy in ways that are hard to predict.
  • Re-pin the goal. Keep the objective and the hard constraints at the top of every turn rather than only at the start of the run. Cheap, and it directly addresses the failure above.
  • Design tools to return less. A tool that returns a file path instead of a file, a count instead of the rows, the three relevant lines instead of the log - that is the highest-leverage change available, and the one teams reach for last. Tool design is context design; a verbose tool costs you on every single call it makes.

Writing intermediate results to disk and passing references is the general form of the third point. The agent keeps a pointer; the data lives somewhere it is not being re-read on every turn.

Compounding errors

An error early in a chain does not stay contained. Step 4 reads the wrong file, step 5 summarises it faithfully, step 6 makes a decision from that summary, and by step 12 the run is a carefully constructed answer to a question nobody asked. The model is not re-litigating step 4; it is building on it.

What makes this genuinely dangerous is that the transcript reads well. Given a bad observation, a capable model produces a coherent next step - that is what it is good at. Coherence is not a signal of correctness here, and reviewing an agent transcript for plausibility will not catch it. The run looks fine right up until you check the output against reality.

The countermeasures are mechanical rather than conversational:

  • Cheap verification between steps. Does the file exist. Does the test pass. Does the row count match what the previous step claimed. Checks a computer can run, not a judgement the model makes about its own work.
  • Checkpoints. Record verified state so a failed run resumes from the last good step rather than starting over. This also caps the blast radius: everything after the checkpoint is suspect, everything before it is not.
  • Shorter runs. The most underrated fix. Two five-step runs with a human glance in between fail far less often than one ten-step run, for exactly the arithmetic reason in section 01.

Silent partial success

This is the one that costs real money, and it is the least discussed. The agent was asked to do ten things. It did eight. No tool errored, no budget was hit, and the final message says the work is complete. The summary is not a lie - it accurately describes what the agent did. It is simply silent about what it did not.

The mechanism is structural, not a model defect. In most agent designs, "am I done?" is answered by the model, judged against a goal it may only partly still have in context (section 03), using evidence it selected for itself. Every input to that judgement is under the control of the thing being judged. A system built that way will sometimes conclude it is finished, and it will be sincere about it.

Which points at the only real fix: the definition of done has to live outside the agent.

  • Make completion checkable by the runtime. Three invoices in, three drafts out. A file at a known path. A row count. A schema that validates. If the harness cannot verify completion without asking the model, the run is unverified.
  • Have the agent emit a structured artifact, not a narrative. A prose summary is unfalsifiable. A list of items with statuses can be counted and compared against the input.
  • Treat hedged language as a signal. "Mostly", "the majority of", "I was unable to locate" appearing in a success summary should route the run to a human rather than to the next stage.
  • Sample completed runs. Not the failures - those are already visible. Pull a handful of successes each week and check them properly. This is the only way most teams discover the problem exists at all.

This is the point where evaluation stops being a nice-to-have. A chatbot's answer is wrong in front of you. An agent's twenty hidden steps produce something plausible, and plausible is the default output of a system that is optimised to be plausible.

Tool results the model cannot use

A surprising share of agent failures are not agent failures at all. They are tools returning things a model cannot act on, and the model doing something reasonable with an unreasonable input.

The recurring offenders are specific and fixable:

  • Ambiguous emptiness. A tool that returns [] for "no matching records" and also for "your query was malformed" has told the model nothing. One means stop looking; the other means try again differently. Distinguish them.
  • Success codes wrapping failures. HTTP 200 with an error object in the body. The harness records a successful call; the model reads it as progress.
  • Unbounded output. A 500-line stack trace or an entire HTML page. The relevant line exists somewhere in there, and it just cost you 4,000 tokens of context (section 03) to include it.
  • Errors written for humans. A message that assumes a reader who can open a dashboard is useless to a reader whose only options are the tools in its own list.

The same care applies to how tools present themselves. The model chooses between tools by reading their names and descriptions - that text is not documentation, it is the selection interface. Two tools with overlapping descriptions produce a model that picks the wrong one and then works hard to make the result fit. Standardising this surface is a large part of what Model Context Protocol is for, though the protocol only carries the description - writing a good one is still on you.

Designing for failure

None of the above argues against agents. It argues against a particular way of building them: one long autonomous run, judged complete by the thing that performed it, reviewed by a human reading a summary. That design fails in all five ways described here, and it is the design most first attempts land on because it is the one the demos show.

What production systems converge on instead is a set of moves that share one idea - make failure cheap, visible, and recoverable rather than trying to eliminate it:

  • Budget everything. Iterations, wall clock, and spend, enforced outside the model.
  • Narrow the job. Fewer tools and a smaller goal means fewer branches, less context, and a shorter chain to verify. This is most of the argument for several specialist agents over one general one.
  • Verify mechanically. If a check requires the model's opinion, it is not a check.
  • Checkpoint. So a failure costs you one step, not the whole run.
  • Put the human at the boundary. Reviewing a structured result at the end beats approving twenty steps in the middle - and unlike step-by-step approval, it stays useful once trust builds.

The gap between an agent that demos well and one you can leave running is almost entirely this list. It is unglamorous work, and it is the work.