Malformed Tool Output Parsing Failures in Multi-Step Agents
Silent failures poison multi-step agents long before anyone notices the wrong answer.

Multi-step agents don't fail the way a normal program fails. A bad tool call in a single-integration setup throws an exception, someone sees a stack trace, someone fixes it. In a multi-step agent chain, a malformed tool output very often arrives looking exactly like a well-formed one, and the agent just keeps going. It doesn't stop. It builds on the bad data, confidently, for as long as nobody's watching.
Why multi-step agents don't just fail (they fail forward)
Engineers coming from single-tool integrations carry an assumption that doesn't hold up here: if something goes wrong, the system will tell you. A null pointer, a 500, a malformed JSON body, something throws, someone gets paged, the bug gets fixed before it does real damage.
Multi-step agents don't work that way. When one step in a chain returns something malformed but still shaped roughly like valid output, the next step consumes it as fact. There's a documented production incident where a cached HTTP error page got fed into an agent as if it were real content, and the agent produced a fully-formed, confident, entirely fabricated analysis on top of it. In that same runtime, 70% of silent failures were only caught because a human happened to read the output and noticed something was off.
The system wasn't crashing 70% of the time. It was wrong 70% of the time, and confident about it, and nobody knew until a person looked closely enough to catch it by hand. That's not a bug rate. That's a trust problem.
LLM tool calling and its importance for output parsing
Tool calling gets talked about like it's a deterministic function call, the same way a client for a standard web API hits an endpoint and gets back a typed response. It isn't that; tool calling is a language model generating tokens that happen to resemble a function call, wrapped in JSON structure after the fact. Tool calling is a language model generating tokens that happen to resemble a function call, wrapped in JSON structure after the fact. The model is guessing at the shape of a good answer, not executing a contract.
That distinction matters enormously for parsing. If the tokens come out slightly malformed, or the schema drifts from what the downstream code expects, or the provider times out mid-generation, the failure doesn't always announce itself. Sometimes it does: a JSONDecodeError, a Pydantic validation error, a clean 400 or 422 from a downstream API, or a retry storm appears in the logs. Those are the visible failures, and they're the easy ones, because something screams.
The dangerous failures are quiet. Application code sees a string like "123.40" and silently coerces it into a number. A missing field gets filled with a default nobody asked for. An unknown key just gets dropped on the floor. None of that raises an exception. All of it corrupts state. LLM output parsing, at its core, is the discipline of turning raw model text into a structured object software can actually trust, and the quiet failures are what that discipline is supposed to catch before they spread.
The seven failure modes that dominate production tool chains
Production taxonomies of agent failures converge on roughly seven recurring failure modes in tool chains. Each one is a distinct mechanism, and each one shares the same dangerous property: none of them necessarily throws a hard exception, so the chain keeps running.
Silent data corruption happens when a tool returns output in the wrong format and the agent passes it forward without noticing. No exception, no flag, just a slightly wrong value moving downstream as if it were correct.
Context loss shows up when key data from an early call gets pushed out of the context window, or diluted across a long conversation. Even with large context windows, models lose fidelity on information buried in the middle of long inputs, and a constraint the user stated at step one can quietly vanish by step five.
Cascading hallucination occurs when a tool returns partial or missing output and the agent fills the gap with a plausible-sounding fabrication, then keeps going as if nothing happened. One recurring example: a financial comparison task where earnings come back in the wrong currency, the agent runs the comparison anyway, and the final summary presents the wrong numbers with total confidence. No error thrown anywhere in the chain.
Tool misuse is the agent calling the wrong tool, or the right tool with wrong parameters. Published research breaks tool misuse into several distinct error types, including incorrect argument values, incorrect argument names, incorrect argument types, hallucinated function names, insufficient API calls, and redundant repeated API calls.
Timeout cascade happens when one slow tool call backs up everything behind it: subsequent steps wait, fail outright, or get served a stale cached response that gets treated as fresh data.
Error swallowing is a tool returning a 500 and the agent, instead of surfacing that failure, generating a reasonable-sounding response as if the call had succeeded. The failure never reaches the caller.
Tool poisoning is subtler and more adversarial: a tool's own description carries hidden instructions, an indirect prompt injection, that fires the moment the agent selects that tool. One vendor's 2026 production failure categories name a variant of this specific to one agent communication protocol as its own class.
Every one of these can occur without a crash. They don't halt the chain, they just poison it. And that's what makes what happens next so hard to catch.
How a single bad parse becomes a chain-wide failure
The cascade has a predictable shape. Step one returns output that's slightly malformed, not broken enough to error out, just off. Step two accepts it and misinterprets a field somewhere in the structure. By step three, the whole chain is confidently wrong, and nothing in the system has thrown an error at any point along the way.
Traditional software doesn't propagate errors like this, because traditional software throws on bad input. LLM tool chains don't share that reflex. The agent treats malformed output as valid input, because from the model's perspective, it is input, shaped correctly, sitting in the expected slot, ready to be reasoned over. Error propagation has been identified as the single biggest barrier standing between current agent architectures and anything resembling dependable production behavior.
Multi-agent systems make this worse, not better. When agents pass outputs to other agents, there's a transitive trust problem baked into the architecture: each agent in the chain implicitly trusts the output of the agent before it, with no independent verification step in between. A single wrong output at the start of the chain doesn't just affect the next step. It propagates through every step after it, unverified, the entire way down.
Why the observed failure rarely matches its origin point
The point where a failure becomes visible is almost never the point where it started; an attribution analysis of 73 production agent incidents logged between January and May of 2026 (from.tech's multi-step failure attribution work) found that 61% of multi-layer failures traced their r... An attribution analysis of 73 production agent incidents logged between January and May of 2026 (from.tech's multi-step failure attribution work) found that 61% of multi-layer failures traced their root cause back to an upstream layer, retrieval or planning, not to the tool call where the failure actually appeared.
The illustrative case is a web search task that fails at the final step, reporting "no results found." The obvious place to look is the search call itself. But the actual root cause, in the case documented, sat one layer up: an earlier agent had formulated an overly restrictive query, and the search tool did what it was told. The final agent is reporting an accurate result on a bad input, and every downstream fix aimed at that final step is fixing the wrong layer. It's reporting an accurate result on a bad input, and every downstream fix aimed at that final step is fixing the wrong layer.
That mislocation has a real cost. Teams that debug at the output layer, tightening the parser, adding retries right at the point where the failure became visible, leave the actual upstream cause untouched. The chain will fail again on the next run, in a slightly different shape, because nothing about the planning or retrieval step that generated the bad input has changed.
A consistent finding across agent failure taxonomies is that the failures are architectural, not a symptom of model quality. Swapping in a better base model won't close this gap, because the taxonomy of failures is a systems-design problem, not a capability ceiling. Fixing it means fixing how information moves between layers, not just how well any one layer reasons.
Schema drift: the slow-moving failure that breaks production chains without an error message
Schema drift is a different animal from a malformed parse, and it deserves to be treated separately. A malformed output is a one-off mistake in a single response. Schema drift is what happens when the tool itself changes shape over time, and the agent's internal model of that tool doesn't change with it.
The classic pattern: a backend renames user_id to member_id. The model keeps generating user_id anyway, because every example, every cached trace, every few-shot prompt in its context still encodes the old key. Or a field like region, which used to have a safe server-side default, becomes mandatory with no client-side default. The model omits it, the same way it always has, and the call "succeeds" at the tool boundary while failing somewhere further downstream, in a way that's much harder to trace back.
A representative cascade traces back to a single underspecified field. A calendar agent, told to book a meeting at "3 PM tomorrow," generated 2025-09-15T15:00:00 with no timezone marker. The tool interpreted that timestamp as UTC by default. For a user sitting four hours behind the timezone the system assumed, the meeting landed on the calendar at 11 AM, four hours off from what was requested, and customer escalations followed. The fix in cases like this isn't a smarter model, it's making the ambiguous field required, or forcing an explicit default, directly in the schema contract, so the ambiguity can't exist.
There's a related problem across tool boundaries, not just within one tool over time. customer_id returned by Tool A might sit in a completely different namespace than customer_id expected by Tool B. Both calls return a clean success. Nothing errors at either boundary. The downstream behavior is simply wrong, and there's no exception anywhere in the trace pointing at why.
The defenses: treating every tool output boundary as an enforced contract
The fix requires a shift in how tool output gets treated architecturally. Tool output is untrusted external input, exactly like a form submission from an anonymous user, even though it came from a system component instead of a user, and it needs to be validated before the next step in the chain is allowed to touch it. It's untrusted external input, exactly like a form submission from an anonymous user, and it needs to be validated before the next step in the chain is allowed to touch it.
That validation stacks in three layers, each catching something the layer before it can't. Structural validation checks whether the output is even parseable. This layer catches truncated JSON, trailing commas, markdown code fences wrapped around a JSON blob, mixed prose and JSON in the same response, or a root type that's an array when an object was expected.
Schema validation goes further and enforces an actual typed contract: required fields present, types correct, enum values inside the allowed set, numeric values inside sane bounds. Tools like JSON Schema, Pydantic, or Zod do this work well. Something important to hold onto here: output can be perfectly valid, parseable JSON and still violate the schema completely. Those are two separate failure classes, and treating them as one is how teams end up thinking their parsing is solid when it's only solid at the syntax level.
Content validation is the layer no schema can express on its own, because it requires knowledge of the domain, not just the shape of the data. A refund amount has to be less than the order total. A citation has to actually exist in the source corpus. A confidence score has to fall inside a calibrated, meaningful range. Catching violations here usually means either explicit domain logic or a judge model checking the output against business rules the schema was never built to enforce.
A handful of mistakes appear again and again in teams that think they've already solved this. Treating parsing as solved once JSON syntax checks out, when a perfectly parseable object can still violate every field-level rule that matters. Patching bad output with regex papers over the real failure and reliably breaks the moment a nested object, an escaped quote, an array, or non-English text appears. Trusting a provider's native function-calling feature as if it were a complete solution: it does cut down on raw syntax errors, but it does nothing to stop business-schema drift, enum mismatches, or a downstream API quietly moving to a new version. And retrying a failed call without passing the validation error back into the prompt, which just means the model repeats the same mistake, because it has no idea what it got wrong the first time.
One documented result makes the case for doing this properly better than any abstract argument could. A coding agent returning unparseable responses at an 8% rate got brought down to 0.3% unparseable and 0% wrong-type errors, using nothing more exotic than a Pydantic model wrapped around the response, paired with automatic retry-with-error-feedback capped at three attempts. That's not a new model. That's not a bigger context window. It's a validated contract at the boundary, doing the job a validated contract is supposed to do.


