Claude Code Structured Output Mode in 2026: Forcing JSON Responses From Subagents and Validating Them With Zod A developer documented how Claude Code's structured output mode forces subagents to return schema-validated JSON instead of prose, using Zod schemas converted to JSON Schema and passed as an outputFormat to startSubagent(). The approach, demonstrated on Claude Code SDK v0.3.301 with Claude Fable 5.1, wraps a subagent's final response in a synthetic tool call validated against the schema, with a SubagentStop hook catching violations before they reach the lead agent's context. The writeup notes that invalid schemas now fail at startup as of SDK v2.1.205, and that failed validations surface as error_max_structured_output_retries after a default of three attempts. This article was written with the assistance of AI, under human supervision and review. Subagents in Claude Code return unstructured text by default. When a lead agent spawns five parallel subagents to extract metadata from API endpoints, the lead receives five prose summaries. Parsing those summaries for the actual data means regex patterns, fallback heuristics, and silent failures when a subagent changes its response format mid-conversation. Problem flow showing subagent returning unstructured text that the lead must parse Structured output mode forces subagents to return validated JSON that matches a schema you define. The lead receives the exact shape it expects, and Zod validates every field before the result reaches the lead's context. No parsing, no silent failures. Solution flow showing subagent returning validated JSON schema This post shows how to pass outputFormat to subagent sessions, validate structured output with Zod before results surface to the lead, and compose JSON schemas for multi-agent workflows that demand reliability. Examples run on Claude Code SDK v0.3.301 with Claude Fable 5.1 claude-fable-5-1 , which dropped support for tool choice types any and tool in the September 1, 2026 release. The structured output and strict tool use patterns here replace the removed tool-choice guarantees. Claude Code structured output validation workflow outputFormat: { type: "json schema", schema: zodSchema } to startSubagent to constrain a subagent's final result. .toJSONSchema schema, { target: "draft-7" } and provide TypeScript types through inference. SubagentStop hook fires before a subagent's result reaches the lead, so Zod validation there catches schema violations before context pollution. additionalContext . Structured output mode wraps the subagent's final response in a synthetic tool call. The SDK generates a tool definition from the schema you provide, instructs the model to call that tool with the result, validates the call against the schema, and surfaces the validated JSON to the lead. The subagent still uses any tools it needs during execution Grep, Bash, file operations , but the final turn must conform to the structure you defined. Conceptual flow of structured output mode transforming subagent result into synthetic tool call The schema is a JSON Schema object. Zod schemas convert to JSON Schema with zodToJsonSchema from the zod-to-json-schema package. The SDK supports standard JSON Schema features: object, array, string, number, boolean, null, enum, const, required, nested objects, and $ref definitions. The format keyword like "format": "email" is accepted as an annotation but not enforced. Before SDK v2.1.205, invalid schemas were silently ignored and the subagent returned unstructured text. After v2.1.205, an invalid schema fails the run at startup with an error naming the problem. The subagent attempts the synthetic tool call up to the retry limit default 3 . If validation fails on every attempt, the result becomes an error of type error max structured output retries . The lead sees the error in the subagent's summary unless your SubagentStop hook intercepts it first. Production workflows often validate in the hook and handle the error there, so the lead never receives a malformed payload. A subagent session accepts outputFormat in the same shape as the lead's query call. Define a Zod schema, convert it to JSON Schema, and pass it to startSubagent . The example below spawns a subagent to extract repository metadata and return it as a typed object: js import { z } from "zod"; import { zodToJsonSchema } from "zod-to-json-schema"; import { startSubagent } from "@anthropic-ai/claude-agent-sdk"; const repoMetadataSchema = z.object { name: z.string .describe "Repository name" , primaryLanguage: z.string .describe "Primary programming language" , stars: z.number .int .nonnegative .describe "Star count" , openIssues: z.number .int .nonnegative .describe "Open issue count" , lastCommitDate: z.string .describe "ISO 8601 date of last commit" } ; type RepoMetadata = z.infer