Why Computer-Use Agents Break JSON: Multi-Step Agent JSON Error Handling (2026)
Computer-use and multi-step LLM agents break JSON in 5 predictable ways. Learn how schema rot, token truncation, and tool argument drift corrupt agentic pipelines — and how to fix them with validation, constrained decoding, and JSON repair.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →A multi-step LLM agent might emit five tool calls per trace. Each call has its own JSON-schema contract: a planner output, tool arguments, a retriever filter, a critique-step payload, and a final response envelope. One invalid field in step two corrupts steps three through five. The entire pipeline fails — not because the model is bad at generating JSON, but because agentic workflows multiply every small reliability gap.
This is the central JSON problem of 2026: not that LLMs can't write JSON, but that agents chain enough calls that even a 99% success rate per call means a 5% compound failure rate across a five-step trace.
This post covers the five root causes, shows concrete code patterns for catching them, and explains where JSON repair belongs in a production agentic stack.
What Makes Agentic JSON Different
Single-call JSON extraction is a solved problem. OpenAI Structured Outputs hit 99.9% schema compliance. Anthropic tool use hits 99.8%. Gemini schema-constrained output hits 99.7%. If you're extracting a data record in one call with a strict schema, JSON errors are rare enough to treat as exceptions.
Multi-step agents break that assumption in three ways:
- Compounding error probability. A five-call agent at 99.5% per step has a 97.5% success rate. Scale to ten steps and you're at 95.1%. Add a computer-use agent reading UI state on top and you're under 90% without explicit recovery logic.
- Context contamination. In a multi-turn agent trace, each step's JSON output becomes part of the next step's context. A malformed string in step two — say, an unescaped newline from a UI label — propagates forward. By step four, the model is trying to reason about broken context it treats as ground truth.
- No synchronous correction. In a human-in-the-loop system, a person catches a bad value before it cascades. In an autonomous agentic loop, the error propagates until something hard-fails — or worse, silently produces wrong output.
The 5 Root Causes of Agent JSON Failures
1. Schema Rot on Tool Arguments
The most common failure in 2026 agent stacks is tool argument rot: malformed JSON, missing required fields, wrong data types, and silent type coercions. A model that reliably produces the right JSON shape often produces unreliable JSON content — values that parse correctly but fail schema validation.
The distinction matters. A schema validation failure is not the same as a JSON parse error. The response is syntactically valid JSON; it just doesn't conform to what the tool expects. In production, schema failures account for the majority of structured-output bugs because parse errors are caught immediately, while schema failures slip through into application logic.
import json
import jsonschema
tool_schema = {
"type": "object",
"properties": {
"order_id": {"type": "string"},
"quantity": {"type": "integer"},
"status": {"type": "string", "enum": ["pending", "shipped", "delivered"]}
},
"required": ["order_id", "quantity", "status"]
}
def validate_tool_args(raw_output: str) -> dict:
try:
data = json.loads(raw_output)
except json.JSONDecodeError as e:
# Level 1: syntax error — attempt repair before giving up
from jsonrepair import repair_json
data = json.loads(repair_json(raw_output))
# Level 2: schema validation — always run, even on syntactically valid JSON
jsonschema.validate(data, tool_schema)
return data
Always run schema validation between each LLM call and the next tool invocation. Parse errors and schema errors need separate handling strategies.
2. Computer-Use Agents Reading Uncontrolled Text
Computer-use agents navigate software interfaces — web apps, desktop applications, form fields — and extract structured data from what they observe. The JSON problem here is that the source data is user-controlled and unpredictable.
A UI label might contain:
- Unescaped double quotes (
He said "done") - Windows-style backslash paths (
C:\Users\data\output) - Literal newlines inside text fields
- HTML entities that didn't decode (
&,') - Unicode directional characters from RTL text
When a computer-use agent reads these values and packs them into a JSON payload, any of them can break the output. Azure AI Foundry agents have been logging intermittent failures with the error "The input does not contain any JSON tokens" — the root cause is often the agent returning an empty or malformed response after reading a UI element with problematic characters.
import re
def sanitize_ui_text(text: str) -> str:
"""Pre-clean text from UI extraction before packing into JSON."""
# Remove control characters (tabs, newlines, carriage returns in string values)
text = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', text)
# Normalize line endings to space (JSON strings can't have raw newlines)
text = text.replace('\r\n', ' ').replace('\r', ' ').replace('\n', ' ')
# Normalize Windows paths — double the backslashes
text = text.replace('\\', '\\\\') if '\\' in text and not text.startswith('"') else text
return text.strip()
This sanitization step belongs before JSON serialization, not after. Fixing broken JSON is harder than not breaking it.
3. LLM Token Truncation Mid-Output
Token truncation is the most common source of structurally broken JSON in agentic workflows. It happens when:
- The model hits its
max_tokenslimit mid-generation - The combined context of prior steps has grown too large, leaving less budget for the current output
- A long planner output or retriever result earlier in the trace ate into the token window
The result is JSON that starts correctly and stops abruptly — an unterminated string, a missing closing bracket, or a cut-off array. See the JSON unterminated string error guide for the full taxonomy of truncation failures.
from jsonrepair import repair_json
import json
def safe_parse_agent_output(raw: str, step_name: str) -> dict | None:
"""Parse agent output with repair fallback. Log repair events for monitoring."""
try:
return json.loads(raw)
except json.JSONDecodeError:
try:
repaired = repair_json(raw)
result = json.loads(repaired)
print(f"[WARN] Repaired JSON at step '{step_name}' — monitor for truncation")
return result
except Exception:
print(f"[ERROR] Unrecoverable JSON at step '{step_name}' — triggering retry")
return None
Budget token limits explicitly per step. A common pattern is to estimate output token requirements for each stage and set max_tokens accordingly, rather than using a single global limit that gets exhausted in long traces.
4. Critique-Step Contamination
Many agentic architectures include a self-critique or verification step where the model reviews its own prior output. These steps often return structured JSON with fields like {"valid": false, "issues": ["field X is missing"]}. The problem is that the model may quote or embed the prior JSON as a string value — and if the prior JSON contained errors, those errors appear inside the new JSON.
// Broken: prior malformed JSON embedded inside critique output
{
"valid": false,
"prior_output": "{"order_id": "123", "status": PENDING}",
"issues": ["status is not quoted"]
}
The outer JSON is now invalid because the inner { from prior_output breaks the string boundary. This is a serialization mistake, not a model error — the fix is to always instruct the model to wrap embedded JSON in escaped strings or to use a structured field reference rather than embedding raw JSON.
# In your critique-step prompt
CRITIQUE_PROMPT = """Review the tool output below and return a structured critique.
DO NOT include the original JSON text in your response.
Reference fields by name only (e.g., "the 'status' field is missing").
Tool output to review:
{tool_output}
Respond with this exact schema:
{"valid": boolean, "issues": string[], "fix_required": boolean}
"""
5. Missing Schema on MCP Tool Outputs
With the MCP 2026-07-28 Release Candidate (dropping tomorrow), outputSchema is now supported and validated. In prior MCP versions, tool outputs were untyped — the client received whatever JSON the server returned. Many server implementations shipped untyped outputs that worked fine until a client started depending on the response shape.
Under the new spec, if you declare outputSchema, the protocol validates your tool's return value against it. Servers that previously returned loose JSON will start throwing validation errors at clients that enforce the new spec.
The immediate action for MCP server maintainers: add outputSchema declarations now, run them against your actual tool outputs, and fix any gaps before July 28. See the MCP RC 2026 checklist for the full list of breaking changes.
The Right Defense: L1 + L2 + Repair
Production agentic systems need three layers of JSON defense:
L1 — Parameter Validation (per tool call): Validate tool arguments against the declared input schema before invoking the tool. Reject malformed inputs immediately and retry the generating step. L2 — Schema Validation (per step output): Validate the output of each LLM step against the expected schema for that step. Schema failures (wrong types, missing fields, wrong enum values) need a retry with reinforced prompting, not a parse retry. Repair fallback — Structural recovery: For parse-level failures (truncation, unescaped characters, syntax errors), JSON repair can recover a valid document from a partially malformed one. It belongs between L1 and L2 — fix the structure first, then validate the content.import { repairJson } from 'jsonrepair';
import Ajv from 'ajv';
const ajv = new Ajv({ strict: true });
async function executeAgentStep<T>(
llmCall: () => Promise<string>,
schema: object,
stepName: string,
maxRetries = 2
): Promise<T> {
const validate = ajv.compile(schema);
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const raw = await llmCall();
// L1: try parse, repair if needed
let parsed: unknown;
try {
parsed = JSON.parse(raw);
} catch {
try {
parsed = JSON.parse(repairJson(raw));
console.warn(`[${stepName}] Repaired JSON on attempt ${attempt}`);
} catch {
if (attempt === maxRetries) throw new Error(`[${stepName}] Unrecoverable JSON`);
continue;
}
}
// L2: schema validation
if (validate(parsed)) {
return parsed as T;
}
console.warn(`[${stepName}] Schema validation failed:`, validate.errors);
if (attempt === maxRetries) {
throw new Error(`[${stepName}] Schema validation failed after ${maxRetries} retries`);
}
// On schema failure: retry with errors added to prompt context
}
throw new Error(`[${stepName}] Exceeded max retries`);
}
The key insight: do not collapse all JSON errors into one retry loop. Parse errors and schema errors have different causes and different fixes. Repair + retry works for truncation and escaping issues. Prompt reinforcement works for schema failures (wrong types, missing fields). Mixing them together wastes retries.
Monitoring: What to Track in Production
For a production agentic system, track these four metrics per step, not per trace:
| Metric | What it catches |
|---|---|
json_parse_failure_rate | Truncation, unescaped characters, syntax errors |
json_repair_rate | Structural issues that repair recovered — high rate signals a prompt or token budget problem |
schema_validation_failure_rate | Content issues — wrong types, missing fields, bad enum values |
step_retry_count | Overall reliability proxy — any step with >5% retry rate needs investigation |
A trace-level success metric alone hides which step is the reliability bottleneck. Step-level metrics let you find the weak link and fix it specifically rather than adding global retries that mask the root cause.
Quick Fixes for Common Agent JSON Errors
| Symptom | Root Cause | Fix |
|---|---|---|
JSONDecodeError: Unterminated string | Token truncation or raw newline | Increase max_tokens for step; add repair fallback |
| Valid JSON, wrong schema | Schema rot / model drift | Add L2 schema validation; reinforce type constraints in prompt |
"The input does not contain any JSON tokens" | Computer-use agent returned empty | Sanitize UI text before packing; add empty-response retry |
| Inner JSON breaks outer JSON | Critique step embedding raw JSON | Instruct model to reference fields by name, not embed raw JSON |
| MCP validation error after July 28 | Missing or incorrect outputSchema | Add outputSchema declarations and validate against real outputs |
For any syntax-level error — truncated strings, unescaped characters, missing brackets — try the AI JSON repair tool first. It handles the most common structural failures from token limits and escaping issues without requiring a model retry.
Frequently Asked Questions
Why do computer-use agents break JSON more than regular LLM calls?Computer-use agents read uncontrolled text from UI elements — labels, form fields, page titles — and pack it into structured JSON. That source text can contain characters that are invalid in JSON strings: unescaped backslashes, raw newlines, unmatched quotes. Regular LLM calls generate JSON from a controlled prompt. Computer-use agents inject external data into the JSON generation path, multiplying the chance of invalid characters.
What's the difference between a JSON parse error and a schema validation failure in agents?A parse error means the output isn't valid JSON at all — the document can't be read. A schema validation failure means the JSON is syntactically valid but doesn't match the expected structure: a field is missing, a type is wrong, an enum value is unexpected. Parse errors need structural repair or a regeneration retry. Schema failures need prompt reinforcement or a retry with the validation errors as feedback. They have different fixes.
Should I use constrained decoding (structured outputs) instead of validating?Use both. Constrained decoding at the provider level (OpenAI Structured Outputs, Anthropic tool use, Gemini schema) eliminates most parse errors and type errors. But constrained decoding doesn't catch semantic errors — a value that's the right type but the wrong content. Schema validation with jsonschema or Zod is still necessary for production agentic systems.
JSON repair belongs as a parse-layer fallback between the raw LLM output and your schema validation step. It recovers documents that are structurally damaged (truncated, wrong escape sequences, trailing commas) but can't fix semantic failures. Think of it as a cleanup layer before your real validation logic runs. Don't use it as a substitute for fixing the root cause — a high repair rate is a signal that something upstream needs attention.
How do I handle tool argument rot — schema-valid JSON that has semantically wrong values?Enforce constraints at the schema level where possible (enum lists, min/max ranges, format strings). For values that can't be constrained in schema (like natural language descriptions that should follow a pattern), add a lightweight validation step after schema checks. Log failures with the actual vs expected value for each field — this makes it easy to spot model drift over time and catch it before it becomes a reliability incident.
Does the MCP 2026-07-28 RC change how I should validate tool outputs?Yes. The RC adds outputSchema support, which means MCP clients that enforce the new spec will validate tool outputs server-side before advancing the agent. If your MCP server's tools return loose JSON today, you need to declare outputSchema for each tool and ensure your actual outputs match the schema. The MCP RC 2026 checklist covers all six breaking JSON changes in the new spec.
Further Reading
- JSON Unterminated String Error Fix — the most common truncation error in LLM pipelines
- JSON Missing Bracket Error Fix — structural failures from token limits
- LLM JSON Repair Guide — comprehensive guide to fixing JSON from LLMs
- MCP RC 2026 Checklist — six JSON changes in the July 28 spec
- Pydantic Validation Error in LLM JSON — schema validation errors in Python stacks
- Fix JSON in Python — Python-specific JSON error patterns
Still dealing with broken JSON?
Paste it in and get it fixed in under 1 second — free, no signup, no install. Works with ChatGPT, Claude, n8n, and any AI output.
Fix My JSON Free →Related Articles