NUMERATA

BLOG · EVALUATING

AI agent failure modes,
and how to catch them.

An agent that crashes is a bug report. Somebody sees a stack trace, files it, and it gets fixed. The failures that cost real money are the other kind: the run finishes, the summary is well written, the confidence is high, and the work is wrong. Nothing in your monitoring moves, because from the outside a wrong answer and a right answer are both a completed run.

Most teams learn this in the same order. They ship an agent, watch the success rate, and it looks fine. Then somebody downstream finds a reconciliation that was never actually reconciled, or a report built on a number no tool ever returned, and the question becomes: how long has this been happening, and how would we know?

The answer to the second half is that you would not, unless you built for it. What follows is the taxonomy that matters in production: eight failure modes worth naming, the specific signal that catches each one, and what to do when it fires. The names are less important than the fact that they are distinct. Each one has a different detector, a different recovery, and a different owner, and a team that treats agent failure as one undifferentiated category ends up with one undifferentiated response to it, which is usually a retry.

The short version

Failure enters at a specific stage of the loop. The agent can misread the world, act wrongly on it, or misdescribe what it did. Three families, and the third one is the expensive family.

Loudness and cost are inversely related. A malformed tool call is caught in the same turn it happens. A silent partial completion is caught by someone downstream, weeks later, if at all. The modes that are easiest to detect are the ones that matter least.

The report is not evidence. The summary is the part of the output the agent controls most and grounds least. Every check worth running compares the report against the trace, or skips the report entirely and checks the end state.

Detection is three layers, and most teams have two. Turn-level invariants run inside the loop and are blind to the expensive modes. End-state verification is the truth and cannot run on live traffic. The layer in between is the one that is usually missing.

Some of this is not a model problem. Two of the eight modes are fixed by permissions and protocol, not by training. Knowing which is which is most of the value of naming them.

Where failure enters the loop

An agent run is one small cycle repeated: look at the state, decide on an action, call a tool, interpret what came back, and eventually report. That structure is what makes agents useful and it is also what makes them fail differently from a single model call. A chat completion is wrong or right in one shot. An agent has twenty chances to go wrong, each one conditioned on the output of the last, and errors compound rather than average out.

It also means failure is not a single event with a single cause. It enters at a stage, and the stage tells you which detector could possibly have caught it.

The agent loop and the failure modes that enter at each stage One turn of an agent loop runs through four stages: plan, act, interpret, and report, then returns to plan for the next turn. Eight named failure modes sort into three families by the stage they enter at. Misreading the world covers goal drift and context decay, which enter at the plan stage, and empty-result fiction, which enters at interpret. Acting wrongly on the world covers malformed tool calls, doom loops, and unauthorized side effects, all of which enter at the act stage. Misdescribing what it did covers silent partial completion and cascade through a handoff, both of which enter at the report stage and are invisible to the loop itself. ONE TURN OF THE LOOP. EACH STAGE FAILS ITS OWN WAY. PLAN ACT INTERPRET REPORT NEXT TURN, CONDITIONED ON THE LAST 1 · IT MISREADS THE WORLD GOAL DRIFT STAGE: PLAN CONTEXT DECAY STAGE: PLAN EMPTY-RESULT FICTION STAGE: INTERPRET 2 · IT ACTS WRONGLY ON IT MALFORMED CALL STAGE: ACT DOOM LOOP STAGE: ACT SIDE EFFECT STAGE: ACT 3 · IT MISDESCRIBES WHAT IT DID SILENT PARTIAL STAGE: REPORT HANDOFF CASCADE STAGE: REPORT NEITHER IS VISIBLE TO THE LOOP ITSELF. THE STAGE TELLS YOU WHICH DETECTOR COULD HAVE CAUGHT IT.
Family 3 is the one that finishes the run, reports success, and is wrong.

The eight, named

1. Goal drift. The task the agent is working on at turn twenty is not the task it was given at turn one. Nothing dramatic happens; each turn is conditioned on the agent's own restatement of the work, restatements lose qualifiers, and after enough of them the qualifier that made the request specific is gone. Ask for the cash break on one book and get a careful, correct, well-presented answer about the whole desk. The tell is that the output is good. It is a competent answer to a question nobody asked.

2. Context decay. The goal survives but a constraint does not. "Read-only", "staging only", "exclude the internal counterparties" holds for six turns and then quietly stops holding. This is worth separating from drift because the symptom is different: the run starts compliant and ends non-compliant, so a spot check on the first few turns finds nothing wrong. Constraints stated once in prose, in the middle of a long instruction, are the ones that go first.

3. Empty-result fiction. A tool returns zero rows, a null, or the worst case, HTTP 200 with an error in the body. The agent treats absence as a gap to fill and supplies a plausible value. This is the most damaging mode in any numerical domain, because the fabricated output is formatted exactly like a real one and there is no downstream signal that distinguishes them. It is also the mode most obviously worsened by good prose: a model that writes well makes a fabricated reconciliation read like a finished one.

4. Malformed tool call. Wrong argument name, a string where the schema wants an epoch, an enum value that does not exist, a required field invented from a similar public API. This is the loud one, it is caught by schema validation in the same turn it happens, and it traces back to a model that has read every public API reference and none of yours. It is also the mode most people mean when they say their agent is unreliable, which is unfortunate, because it is the cheapest of the eight to fix. See tool-use fine-tuning for the specific remedy.

5. Doom loop. The agent repeats an action that cannot succeed. Sometimes literally the same call twelve times, more often a short cycle: the call fails, the agent calls something diagnostic, reads it, and makes the same failing call again. Budget goes to zero and nothing is produced. Loops are easy to detect and almost never detected, because the naive check looks for identical consecutive calls and a two-step cycle is not consecutive.

6. Unauthorized side effect. A write outside the permitted surface. The important property of this mode is that it can coexist with a correct answer, which is why it has to be counted as a failure on its own terms rather than folded into a correctness score. An agent that produced the right number after updating a table it should never have touched did not pass, and a scoring scheme that says otherwise is training you to ignore it.

7. Silent partial completion. The job needed five steps. Three ran. The summary says the job is done. This is the single most expensive mode in the list, not because it is the most common but because the detection lag is measured in weeks and the discovery is almost always external. Somebody downstream finds the hole, and by then the same agent has done the same thing a few hundred more times.

8. Handoff cascade. In any setup with subagents or a chain of specialists, an upstream agent's guess arrives downstream as an established fact. The uncertainty is stripped at the boundary, because what crosses the boundary is a conclusion and not the reasoning that produced it. The receiving agent has no way to know the difference and treats it as a premise. One soft guess early becomes a firm and completely wrong conclusion three hops later, and the trace of the final agent looks impeccable.

The detection lag is the actual cost

Rank those eight by how bad they are and you get roughly the reverse of how loud they are. The mode that fires an exception is cheap. The mode that files a well-formatted report is not.

How long each failure mode typically goes undetected A bar chart of typical detection lag by failure mode. Malformed tool calls are caught in the same turn. Doom loops and unauthorized side effects are caught within the same run, assuming the run has budget counters and a write allowlist. Goal drift and context decay are caught only when somebody reviews the trajectory. Handoff cascade and empty-result fiction typically take weeks. Silent partial completion is normally found by somebody downstream rather than by any monitoring, which is the longest lag of the eight. The pattern is that the loudest failures are the cheapest and the quietest are the most expensive. TIME UNTIL SOMEBODY NOTICES SAME TURN SAME RUN ON REVIEW WEEKS DOWNSTREAM MALFORMED CALL DOOM LOOP SIDE EFFECT CONTEXT DECAY GOAL DRIFT HANDOFF CASCADE EMPTY-RESULT FICTION SILENT PARTIAL THE THREE AT THE TOP THROW ERRORS. THE THREE AT THE BOTTOM FILE A REPORT. GUESS WHICH ONES YOU HEAR ABOUT.
Every bar past the second gridline is a failure your dashboards currently score as a success.

The signal that catches each one

Nothing above is detectable by watching a success rate, because in six of the eight cases the run reports success. Each mode needs its own signal, and the useful property of a named taxonomy is that the signals turn out to be specific and cheap.

Failure mode What you see The signal that catches it First response
Goal drift A good answer to the wrong question Anchor check: final result against the original request, stored verbatim Roll back, re-plan from the original text
Context decay Compliant early turns, non-compliant late ones Constraint retention: re-assert every constraint against the last turn Move constraints out of prose and into the guard
Empty-result fiction A plausible number with no source Claim-to-evidence: every figure in the summary must cite a tool result Fail closed, and make empty results structurally distinct
Malformed call Tool errors, arguments rejected Schema validation before dispatch Bounded retry with the error fed back
Doom loop Budget consumed, nothing delivered Action hash repeating with no state change in between Halt. Never allow an identical retry
Side effect Often nothing, until an audit Write allowlist, enforced at dispatch rather than reviewed after Halt and escalate. This is a permissions bug
Silent partial A confident summary of unfinished work Step coverage: each required step present in the trace with a status Require structured completion, not prose
Handoff cascade An impeccable trace built on a guess Provenance: confidence and source carried in the handoff schema Propagate uncertainty, or refuse the handoff

LLM agent reliability is three layers, not one

Sort those signals by when they can run and they collapse into three layers with very different properties. This is the part worth internalizing, because the gap is nearly always in the same place.

The three layers of agent failure detection and what each one can and cannot do Detection sorts into three layers. Turn invariants run inside the loop, catch malformed calls, doom loops and side effects, and can halt a live run, but they are blind to the modes where the run completes and reports success. Trajectory checks run over the recorded trace after the run finishes, catch goal drift, context decay, fabrication and partial completion, and can run on a sample of live traffic. End-state verification compares the world against a known-correct answer, catches everything but explains nothing, and cannot run on live traffic because it needs gold answers that only exist for eval tasks. The middle layer is the bridge between the other two and is the layer most teams have not built. WHAT EACH LAYER CAN ACTUALLY SEE CATCHES RUNS ON LIVE TRAFFIC 1 · TURN INVARIANTS MALFORMED · LOOP SIDE EFFECT IN THE LOOP, BEFORE DISPATCH YES, AND HALTS 2 · TRAJECTORY CHECKS DRIFT · DECAY FICTION · PARTIAL AFTER THE RUN, OVER THE TRACE YES, ON A SAMPLE 3 · END-STATE VERIFIER EVERYTHING, BUT NEVER THE WHY ON EVAL TASKS, AGAINST GOLD NO. NEEDS GOLD LAYER 1 IS BLIND TO THE EXPENSIVE MODES. LAYER 3 CANNOT WATCH PRODUCTION. LAYER 2 IS THE BRIDGE, AND IT IS USUALLY MISSING.
Teams tend to build 1 because it is easy and 3 because it is rigorous. The gap in the middle is where the costly modes live.

TURN INVARIANTS

Cheap assertions inside the loop, checked before each tool call: schema valid, target on the write allowlist, budget not spent, action not a repeat of one already tried. Microseconds each, and the only layer that can stop a bad run while it is still bad.

TRAJECTORY CHECKS

Rules and one small model call run over the recorded trace once the run ends: does the answer match the original request, did every constraint hold to the last turn, does every claim in the summary have a source. This is the missing layer.

END-STATE VERIFICATION

The verifier from your eval set, comparing the world against a known-correct outcome. Definitive, and restricted to tasks where a gold answer exists, which means it measures your agent rather than watching it.

Layer one is where everyone starts and it is genuinely worth having, because three of the eight modes stop being possible once it is in place. It is also structurally incapable of catching the other five, since all five produce runs that complete normally with every invariant satisfied.

Layer three is the subject of agent evaluation: a pinned task set, a frozen environment, and a program that decides whether an attempt succeeded. It is the only source of ground truth you will ever have, and it cannot watch production, because production tasks do not come with gold answers.

Which leaves layer two carrying the load, and layer two is unglamorous. It is a handful of checks over a structured trace, and it works only if the trace has the right fields in it.

# Layer 1: invariants, inside the loop, before the call goes out.
def guard(turn, run):
    if not SCHEMA[turn.tool].validates(turn.args):
        return RETRY("malformed", feedback=SCHEMA[turn.tool].error)

    if turn.writes and turn.target not in ALLOWED_WRITES:
        return HALT("side effect")        # permissions bug, not a retry

    if run.spent() > run.budget:
        return HALT("over budget")        # report incomplete, don't summarize

    # A loop is a repeated action with nothing changed in between, which is
    # why comparing to the *previous* call misses every two-step cycle.
    sig = hash((turn.tool, normalize(turn.args)))
    if sig in run.actions_since_last_state_change():
        return HALT("loop")

    return DISPATCH

# Layer 2: over the finished trace, the five things layer 1 cannot see.
#   anchored(run.original_request, run.result)      -> goal drift
#   constraints_held(run.constraints, run.trace)    -> context decay
#   every_claim_sourced(run.summary, run.trace)     -> fiction, partial
#   steps_covered(TASK.required_steps, run.trace)   -> partial
#   provenance_intact(run.inbound_handoffs)         -> cascade

What to log, or none of this works

Every check in layer two reads a field off the trace, so the trace is the real prerequisite and a transcript is not a trace. A wall of interleaved prose and tool output makes the expensive modes structurally invisible, because you cannot write a rule over it.

Per turn, the fields that earn their storage: the turn index, the tool name, a hash of the normalized arguments, the result status kept separate from the result payload, the diff the turn made to any external state, and the running spend in turns, tokens, dollars, and wall clock. Per run: the original request stored verbatim, and the constraints stored as their own list rather than left embedded in the prose that carried them.

Two of those are the ones people skip, and both are the ones the hard modes depend on. Status separate from payload is what makes empty-result fiction detectable, because a 200 carrying an error body is indistinguishable from success unless something unpacked it. The original request, verbatim is what makes goal drift detectable, because the alternative is comparing the result against the agent's own restatement, which drifted with it.

Agent error recovery, matched to reversibility

Detection without a response is just a slower way to find out. The useful sorting principle for the response is not how severe the failure looks but how reversible the action was, because that is what determines whether trying again is cheap or catastrophic.

Agent error recovery matched to what triggered it Five recovery responses matched to five triggers. A mechanical error on a reversible action gets a bounded retry that must differ from the last attempt, capped at two. No progress across two identical actions gets a rollback to the last checkpoint and a re-plan from the original request. An action that is irreversible gets an approval gate before it runs rather than a review afterwards. A fired guard means failing closed and escalating with the whole trace. An exhausted budget means halting and reporting the work as incomplete. Absent from the list is letting the agent try again and see, and absent from every row is letting the agent decide whether it succeeded. WHAT FIRED  →  WHAT HAPPENS NEXT MECHANICAL ERROR, REVERSIBLE RETRY, BUT DIFFERENT. CAP AT TWO. NO PROGRESS, ACTION REPEATED ROLL BACK. RE-PLAN FROM THE REQUEST. THE ACTION IS IRREVERSIBLE GATE IT. APPROVE BEFORE, NOT AFTER. A GUARD FIRED FAIL CLOSED. ESCALATE WITH THE TRACE. BUDGET EXHAUSTED HALT. REPORT IT AS INCOMPLETE. NOT ON THE LIST: LET IT TRY AGAIN AND SEE WHAT HAPPENS.
Five triggers, five responses. The agent is not the one that decides which row it is in.

Retry, but never identically. A retry that sends the same call is the mechanism of the doom loop, not a defence against it. Feed the error text back, require a materially different call, cap the attempts at two, and if the second attempt does not differ from the first, stop rather than let the run spend the rest of its budget discovering the same thing.

Roll back, then re-plan from the original text. Checkpointing is what makes drift recoverable, and re-planning is where teams undo their own work: re-planning from the agent's current understanding of the task simply restarts from the drifted position. Re-plan from the request as the user wrote it.

Gate the irreversible, do not review it. Every workflow has a small number of actions that cannot be undone: the payment, the deletion, the outbound message, the write to a system of record. Gating those with an explicit approval is affordable precisely because they are rare, and the alternative is an incident review that begins after the thing already happened.

Fail closed. When a guard fires, emit nothing. This is the discipline that gets abandoned first, because a partial answer feels more useful than no answer, and it is how a detected failure becomes a shipped one. Escalate with the whole trace attached, since a human asked to adjudicate a run without its trace will do the only thing available, which is to trust the summary.

Underneath all five rows is one rule that is easier to state than to hold: the agent must never be the component that decides whether it succeeded. Self-assessment is the same generation process that produced the work, running on the same context, with the same drift and the same blind spots. It will tell you the run went well, in good prose, for exactly the reasons it went badly.

How your monitoring will lie to you

A team that builds all of the above still gets a dashboard that overstates its position, in five predictable ways.

Retries hide the loops. If the metric is final success, a run that needed three attempts scores identically to one that worked immediately. Track first-attempt success as its own number, or the degradation that precedes a real outage stays invisible until it crosses the retry budget.

The repair masks the defect. A validator that silently fixes a malformed call is doing production a favour and your training set a disservice. Log every repair as a failure that was recovered, otherwise the model's actual schema competence looks perfect right up until you change frameworks.

One run per task proves nothing. Agents are nondeterministic, and an agent that succeeds 85 percent of the time per attempt will look fine the first time you watch it and fail one job in seven forever. Reliability is the fraction of tasks that pass on every one of several attempts, not the average of the attempts.

A judge that reads the summary will believe the summary. The write-up is the most fluent and least grounded part of the output, so scoring it grades the agent's prose. Point the judge at the trace and the end state instead, and it stops agreeing with confident fabrications.

Turn-level numbers flatter you. Ninety-nine percent per-turn success across twenty turns is an eighty-two percent task success rate. Aggregate at the task, always, because the task is the unit the business cares about and the compounding is the whole problem.

Which of these is a training problem

Naming the modes pays off here, because they do not share a fix and the wrong fix is expensive. Three different owners come out of the same eight rows.

Mechanical failures are supervised fine-tuning. Malformed calls, wrong argument names, misread schemas: the model has read every public API reference and none of yours, and demonstrations of your own tools close that gap directly. This is tool-use fine-tuning, and it is the highest ratio of improvement to effort in the list.

Judgment failures are reinforcement learning. Drift, decay, and looping are properties of a whole trajectory rather than of any single step, so there is no correct next token to demonstrate. What you need is a program that scores the finished attempt, which is the verifier from your eval set doing double duty as a reward function. That trade is the subject of SFT versus RL for agents, and the broader shape is agentic fine-tuning.

Fabrication is half training and half interface. The training half is teaching the model that reporting an absence is a rewarded outcome rather than a failure to be papered over, which requires having tasks in your set whose correct answer is "the data is not there". The interface half is making an empty result structurally impossible to confuse with a populated one, so the model is not left inferring it from an empty list.

Two of them are not model problems at all. Unauthorized side effects are a permissions question, and the rule is to never train what you can revoke: an allowlist enforced at dispatch is a guarantee, and a well-behaved model is a probability. Silent partial completion and handoff cascade are protocol questions, fixed by requiring structured completion reporting instead of a prose summary, and by carrying confidence and provenance in the handoff schema so that a guess cannot arrive downstream looking like a fact.

Which is the practical argument for a taxonomy rather than a general sense that agents are flaky. Four of the eight modes get better with training, two get better with plumbing, and two get better with a permissions change you could ship this week. A team that has not separated them tends to reach for the most expensive option available, which is a new model.

Where this fits at Numerata

Numerata's position is that the failure modes above are the reason an agent programme is an infrastructure project rather than a prompt project. P95 treats the trace as a first-class object: runs are recorded with the fields the layer-two checks need, verifiers are versioned alongside the task set, and a failed trajectory is retained as training data rather than discarded as noise, because the run that drifted is the most informative run you have. Rollouts and eval passes draw GPUs from the pool Lupine manages, which is what makes running a task set several times a scheduling question rather than a budget negotiation, and finished checkpoints go to NinetyFive to serve.

The reason this runs inside your own environment is what the traces are made of. A trace of a real agent run contains the request as a person wrote it, the arguments passed to your internal endpoints, the rows that came back, and the definition of a correct outcome. That is a more sensitive artifact than the model weights it is used to improve, and it is not something to ship to a third party in order to find out why last Tuesday's run was wrong. Numerata installs inside your own environment, private cloud, on-premises, or fully air-gapped, so the traces never leave.

If you are earlier in this: agent evaluation covers building the task set and verifier that layer three depends on, tool-use fine-tuning covers the internal-API gap most mechanical failures trace back to, and synthetic data for fine-tuning covers what to do when you have failing trajectories but no labelled corpus to correct them with.

Numerata runs inside your own environment: private cloud, on-prem, or fully air-gapped.  ·  Back to blog