[Bug] Anthropic API Error: Opus 4.8 produces invalid schema-conformant output on large nested CJK payloads; schema retry loops stall workflow
Bug Description
Title: Workflow + StructuredOutput: Opus 4.8 produces invalid schema-conformant output on large/nested CJK payloads; harness retry loops for 8–20 min and stalls the pipeline
Component: Claude Code — Workflow tool, schema-enforced subagent output (StructuredOutput)
Model: claude-opus-4-8 (1M context)
Severity: Medium — no data loss, but burns minutes + tokens per agent and can hang a workflow; failure looks like "still running."
Summary
When a Workflow subagent is invoked with a schema and must emit a large, deeply-nested, CJK-heavy JSON object, Opus 4.8 intermittently fails to produce a valid object. The harness rejects it
(Output does not match required schema: ...) and the agent retries the same malformed shape repeatedly. There is no fail-fast / degrade path, so the agent spins for 8–20 minutes (file mtime
frozen). Because it is a pipeline() stage that never resolves, it stalls downstream stages and the workflow appears to "run" indefinitely.
Two distinct failure modes observed (same root: large structured output is unreliable):
1. Tool-grammar leakage — find agent emitted, inside a JSON string value:
StructuredOutput input={"dimensionAssessment": "...DROP 後 runtime Unknown column 炸。</dimensionAssessment>\n<parameter name=\"findings\">[{\"id\":\"C1\",...
1. The model closed the field with an XML end-tag and opened <parameter name="findings"> — mixing Anthropic's XML-tagged tool-call grammar into what the harness expects as a pure-JSON argument.
It also tried to pass the findings array as a JSON string.
Rejection (repeated ×5): root: must have required property 'findings'
2. Required-field omission on long output — verify agent (different schema) produced valid JSON but dropped a required field 5 times in a row:
{"isReal": true, "adjustedSeverity": "P1", "confidence": "high", "planAlreadyHandles": false, "threeStageEvidence": {"pattern": "...(very long)..."}, "verdict": "..."} ← missing
"fixAssessment"
2. Inputs were 2700–3200 chars; the model appears to exhaust budget on the long threeStageEvidence and omit the trailing required field. Rejection (repeated ×5): root: must have required
property 'fixAssessment'
Key observation: the generic schema-error message does not tell the model what it did wrong or which value to fix, so retries reproduce the same error. Five identical-error retries provided
zero correction signal.
Scale of incident: a ~60-agent review workflow (18 dimensions × find+verify). Agents on "list many files/lines" dimensions (completeness, drop-column enumeration, cross-service writepath) were
the ones that crashed; simple dimensions succeeded.
Impact
- Wasted wall-clock (8–20 min/stuck agent) and tokens on doomed retries.
- A stalled pipeline stage can hang the whole workflow (only a call-site .catch or a retry cap saves it).
- Low observability: /workflows shows "running," not "retry-failing ×5."
Suggested fixes (harness side)
1. Cap schema retries (e.g. 3) then resolve the agent() call to a structured error / null promptly, so .catch / pipeline-drop engages instead of spinning for minutes.
2. Targeted re-prompt instead of generic error: on rejection, tell the model exactly which field is missing/invalid and "emit pure JSON, no XML <parameter>/</field> tags, arrays as arrays not
strings." The generic must have required property X is too weak to correct mode-1 and mode-2.
3. Auto-repair the common mode-1 leakage (strip </field> / <parameter ...> and re-parse) before failing.
4. Degrade to free-text capture after N failures so the finding isn't lost.
5. Surface retry-stall in /workflows ("schema-retry ×5") so it reads as failing, not running.
Workaround that fixed it (user side)
- Shrink the per-agent output: prompt caps (≤N findings/dimension, ≤3 sentences/field, evidence = file:line list only, no pasted code) + an explicit "arrays are top-level params, never stuff
into a string, no XML tags" instruction.
- Restart only the affected agents with Workflow({scriptPath, resumeFromRunId}) — cached agents return instantly, only the edited prompts re-run.
Environment Info
- Platform: darwin
- Terminal: iTerm.app
- Version: 2.1.187
- Feedback ID: 74cbb289-d328-4abe-9dc9-41465710c8d5
Errors
[]This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗