AI agent output parsing failures — malformed JSON and broken structured output
22 patterns
AI agent output parsing failures — malformed JSON and broken structured output. We've tracked 22 distinct AI Output Parsing Failures patterns across production AI agent deployments — most commonly in Operations, Reasoning and Thought, Mortgage Documents systems. One recurring example: Api Version Schema Mismatch — An agent was built and tested against a specific version of a tool's API schema — field names, types, nesting structure, enum values. When the tool vendor ships a new API version w…
Each pattern below documents the specific failure mode, why it happens, and how teams have mitigated it in practice — use this page as a reference when building guardrails, writing evals, or debugging an agent that's already misbehaving in this way.
An agent was built and tested against a specific version of a tool's API schema — field names, types, nesting structure, enum values. When the tool vendor ships a new API version with a changed schema (a renamed field, a restructured nested object, a stricter enum), and the agent's requests still get routed there (via a default-version endpoint, an auto-upgraded SDK, or an account migration), the agent's parsing logic silently misreads or drops fields instead of failing loudly, producing corrupted downstream state rather than a clear error.
An upstream system or team changes the shape of the data it emits — renaming a field, changing a type, adding a required field, deprecating an enum value — without coordinating with every downstream consumer. Because the pipeline has no contract enforcement between producer and consumer, the change ships silently, and the agent's parsing logic either throws on the first unexpected value, silently coerces it to null/default, or misinterprets a renamed field as absent, breaking downstream behavior with no upstream-visible signal that anything happened.
The same tool returns errors in inconsistent shapes depending on which layer of its stack produces the failure — a structured JSON body with an `error.code` field for application-level validation errors, a bare plain-text string for a load balancer timeout, and a full HTML error page for a gateway-level 502 or a WAF block. An agent's error parser, built to expect one shape (usually the documented JSON structure), successfully handles the cases that match it and silently mishandles or crashes on the rest, because the alternate formats don't fail loudly — they just don't match, and the fallback behavior for a non-match is often to treat the response as a generic unknown failure or, worse, to attempt to parse it as JSON and swallow the resulting exception.
An agent interprets a date, number, or currency value using the wrong locale convention — reading "03/04/2026" as March 4th when the source used day-month-year, or parsing "1.234,56" as one-point-two-three-four instead of one thousand two hundred thirty-four point five six. The value parses without error under the wrong locale's rules, so the agent proceeds confidently with a value that is silently different from what the source intended.
An agent's parser (JSON, XML, YAML, or a custom nested-structure format) receives an input with excessive nesting depth — either from a legitimately complex source, a buggy upstream serializer that loops, or a deliberately crafted payload — and the recursive-descent parsing logic exceeds the language runtime's call-stack limit or the parser's own recursion guard, crashing the process rather than rejecting the input gracefully. Because the crash happens inside the parsing library itself, it often takes down the whole request-handling worker rather than failing just the one bad input.
An agent accepts an input payload (a document, a file upload, a JSON body, an attachment) without checking its size against any reasonable bound before processing it, so an unusually large input — whether legitimate, accidental, or adversarial — is loaded fully into memory, tokenized in full, or passed whole into a downstream call, causing memory pressure, request-latency spikes, or costly API usage that a small size check would have caught in microseconds.
An agent's input parsing or downstream rendering logic breaks when the input contains characters with structural meaning in some layer of the pipeline — quotes, backslashes, delimiters (commas, pipes, tabs), markup characters (`<`, `>`, `&`), or control characters — and that layer wasn't written to treat them as literal data. A customer name containing an apostrophe, a product description containing a comma inside a CSV field, or free text containing an unescaped `<` breaks parsing, corrupts a field boundary, or renders incorrectly, independent of any encoding issue.
Individual entries in a persistent memory store can become corrupted — truncated writes from a crashed process, malformed JSON from a partial serialization, encoding mangling, or a bad migration that silently drops or garbles fields — and the retrieval path has no validation step that would catch this before the corrupted entry is handed to the agent. Instead of failing loudly, the agent receives a mangled fact, a broken embedding, or a record with fields swapped and treats it as valid input, often producing a confidently wrong answer that is harder to diagnose than an outright retrieval failure would have been.
A tool caps the memory available to a single operation (a container memory limit, a serverless function's configured RAM, an in-process buffer ceiling). When the agent sends a request whose payload or intermediate working set exceeds that ceiling — a large file upload, a wide JSON response being deserialized in full, a big in-memory join — the operation is killed by an out-of-memory (OOM) reaper and the failure surfaces to the agent as an opaque, non-specific error rather than a clear "payload too large for allocated memory" message.
An agent requests a strictly-formatted response (JSON matching a schema, XML with specific tags, a fixed-width table) and the model complies most of the time, but intermittently deviates — adding prose before the JSON, using a slightly different key name, wrapping output in markdown code fences one call and not the next, or emitting a subtly malformed structure. Because the deviation is intermittent rather than constant, it passes casual testing and only surfaces as parse failures at some rate in production.
Many tools reject JSON or other structured payloads once object/array nesting exceeds a fixed depth — commonly somewhere between 10 and 32 levels — to protect their parsers from stack-exhaustion and pathological-input attacks. Agents that build payloads through recursive composition (e.g., chaining tool outputs into a nested config object, recursively expanding a tree-shaped data structure, or composing several sub-tool results into a wrapper object) can produce structures that grow deeper than intended without any single step looking unusual, because the depth accumulates across composition steps that the agent reasons about independently rather than as a whole.
An agent produces output intended to conform to a specific schema (JSON with required fields, a fixed CSV column set, an API response contract) and hands it directly to a downstream consumer without verifying it actually matches that schema first. Because LLM-generated output is probabilistic rather than mechanically guaranteed, a small but nonzero fraction of responses have a missing field, wrong type, extra field, or malformed structure — and without a validation gate, that malformed output reaches the consumer exactly as if it were valid, causing it to fail unpredictably rather than being caught at the source.
An agent generates text that must be embedded inside a structured format — a JSON string value, a CSV field, a shell argument, a string literal in generated code — and the content itself contains quote characters, apostrophes, or backslashes that need to be escaped for the target grammar. Because the model produces the escaped output as free-form text generation rather than by running a deterministic escaping function, it frequently gets the transform wrong: under-escaping (leaving a raw quote that terminates the string early), over-escaping (doubling an already-correct escape sequence), or escaping for the wrong target grammar entirely (JSON-escaping content destined for a shell command, or vice versa). The result is a downstream parse failure or a corrupted field, distinct from output injection in that no malicious input is required — the model breaks its own well-intentioned output on ordinary content like a customer's name containing an apostrophe.
A pipeline runs agent-generated output through a sanitization step — a blocklist filter, an HTML-stripping function, a pattern-based scrubber — before it reaches a downstream consumer, and the sanitizer genuinely runs and genuinely modifies output that matches its rules. The gap is that the sanitizer's rules cover a specific, enumerable set of dangerous patterns rather than the full space of ways the same underlying danger can be represented: an encoded or obfuscated variant of a blocked pattern passes through untouched because it doesn't match the literal pattern the sanitizer looks for, or content that was safe at the moment it was sanitized becomes dangerous again after a later transformation step (minification, template re-interpolation, client-side re-parsing) that the sanitizer never accounted for. This is distinct from having no sanitization at all — the defense exists, runs, and has a real but incomplete coverage boundary that a sufficiently different-looking payload slips past.
An agent's generated output — a chat completion, a streamed response, or a payload returned from a tool call — gets cut off mid-generation or mid-transmission (hitting a `max_tokens` cap, a proxy timeout, a streaming connection drop, or an intermediate buffer limit), and nothing in the pipeline detects or flags that the content is incomplete. The truncated fragment is syntactically plausible enough (a sentence that just stops, or JSON that's missing its closing braces) that it gets parsed, stored, or displayed as if it were the complete, intended output, rather than triggering a retry or an explicit incompleteness signal.
An agent produces output whose values are of one type — a string, a loosely-formatted number, a mixed-case boolean word — and the downstream system consuming that output performs an implicit type coercion while deserializing or ingesting it, silently converting the value into something semantically different rather than rejecting it. Because the coercion happens inside the consumer's parsing/deserialization layer rather than inside the agent, the agent has no visibility into the mismatch and no chance to correct it; the corrupted value simply propagates into the receiving system as if it were correct.
Tools that return large result sets — search results, exports, list endpoints without server-driven pagination — often cap or silently truncate the response payload above a certain size, and critically, this truncation frequently happens without a clear error or a truncation flag in the response body. An agent that reads such a response, parses whatever JSON or text made it through, and proceeds treats a partial result as the complete answer, leading to decisions, summaries, or downstream actions based on missing data with no indication anything was cut off.
State that an agent writes with one encoding — a character set, a serialization scheme (JSON vs. protobuf field ordering), a number format (float vs. decimal string), or a timezone convention — is later read by a different component that assumes a different encoding. The read succeeds without error but produces subtly wrong values: mojibake in text, truncated precision in numbers, or a timestamp shifted by hours. Because the read doesn't throw, the corruption propagates silently into downstream decisions.
An agent chains the output of one tool directly into the input of another, but the two tools disagree on format — one returns a date as `MM/DD/YYYY` while the next expects ISO-8601, one returns a list under a `results` key while the next expects `items`, one returns plain text while the next expects structured JSON. The agent either passes the mismatched data through unchanged (producing a downstream error or silent misinterpretation) or the LLM performs an ad hoc, occasionally-wrong reformatting step in between.
A project's lock file (`package-lock.json`, `poetry.lock`, `Cargo.lock`, `Gemfile.lock`) pins the exact resolved version of every dependency at the moment it was last regenerated, and that lock file is checked into source control and treated as the source of truth for what actually gets installed in CI and production. Over time, the manifest's version ranges (`^2.1.0`, `>=1.4`) would permit newer releases, but because nobody regenerates the lock file, every install — regardless of how much time has passed — keeps resolving to the same increasingly old exact versions, silently accumulating unpatched vulnerabilities and missed bug fixes while the manifest itself looks perfectly current.