Get structured output from agents changedagent-sdk/structured-outputs
Nearest release: v2.1.293, published 9 hours after upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 7 Oct 2026 07:30 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 20 Oct 2026 18:37 UTC.
Upstream edited
Recorded here
Lines+399added
Lines−409removed
From line
12
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits8to this page, all time
The whole hunk
from line 12, old and new numbered
/
The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.
from line 12
1212
1313Consider a recipe app where an agent searches the web and brings back recipes. Without structured outputs, you get free-form text that you'd need to parse yourself. With structured outputs, you define the shape you want and get typed data you can use directly in your app.
1414
15<AccordionGroup>
16 <Accordion title="Without structured outputs">
17 ```text theme={null}
18 Here's a classic chocolate chip cookie recipe!
19
20 **Chocolate Chip Cookies**
21 Prep time: 15 minutes | Cook time: 10 minutes
22
23 Ingredients:
24 - 2 1/4 cups all-purpose flour
25 - 1 cup butter, softened
26 ...
27 ```
28
29 To use this in your app, you'd need to parse out the title, convert "15 minutes" to a number, separate ingredients from instructions, and handle inconsistent formatting across responses.
30 </Accordion>
31
32 <Accordion title="With structured outputs">
33 ```jsonc theme={null}
34 {
35 "name": "Chocolate Chip Cookies",
36 "prep_time_minutes": 15,
37 "cook_time_minutes": 10,
38 "ingredients": [
39 { "item": "all-purpose flour", "amount": 2.25, "unit": "cups" },
40 { "item": "butter, softened", "amount": 1, "unit": "cup" }
41 // ...
42 ],
43 "steps": ["Preheat oven to 375°F", "Cream butter and sugar" /* ... */]
44 }
45 ```
46
47 Typed data you can use directly in your UI.
48 </Accordion>
49</AccordionGroup>
15> **Without structured outputs**
16>
17> ```text theme={null}
18> Here's a classic chocolate chip cookie recipe!
19>
20> **Chocolate Chip Cookies**
21> Prep time: 15 minutes | Cook time: 10 minutes
22>
23> Ingredients:
24> - 2 1/4 cups all-purpose flour
25> - 1 cup butter, softened
26> ...
27> ```
28>
29> To use this in your app, you'd need to parse out the title, convert "15 minutes" to a number, separate ingredients from instructions, and handle inconsistent formatting across responses.
30
31> **With structured outputs**
32>
33> ```jsonc theme={null}
34> {
35> "name": "Chocolate Chip Cookies",
36> "prep_time_minutes": 15,
37> "cook_time_minutes": 10,
38> "ingredients": [
39> { "item": "all-purpose flour", "amount": 2.25, "unit": "cups" },
40> { "item": "butter, softened", "amount": 1, "unit": "cup" }
41> // ...
42> ],
43> "steps": ["Preheat oven to 375°F", "Cream butter and sugar" /* ... */]
44> }
45> ```
46>
47> Typed data you can use directly in your UI.
5048
5149## Quick start
5250
from line 52
5452
5553Before running the examples on this page, install the Claude Agent SDK by following the [quickstart](/docs/en/agent-sdk/quickstart#setup). The example below asks the agent to research Anthropic and return the company name, year founded, and headquarters as structured output.
5654
57<CodeGroup>
58 ```typescript TypeScript theme={null}
59 import { query } from "@anthropic-ai/claude-agent-sdk";
60
61 // Define the shape of data you want back
62 const schema = {
63 type: "object",
64 properties: {
65 company_name: { type: "string" },
66 founded_year: { type: "number" },
67 headquarters: { type: "string" }
55```typescript TypeScript theme={null}
56import { query } from "@anthropic-ai/claude-agent-sdk";
57
58// Define the shape of data you want back
59const schema = {
60 type: "object",
61 properties: {
62 company_name: { type: "string" },
63 founded_year: { type: "number" },
64 headquarters: { type: "string" }
65 },
66 required: ["company_name"]
67};
68
69try {
70 for await (const message of query({
71 prompt: "Research Anthropic and provide key company information",
72 options: {
73 outputFormat: {
74 type: "json_schema",
75 schema: schema
76 }
77 }
78 })) {
79 // The result message contains structured_output with validated data
80 if (message.type === "result" && message.subtype === "success" && message.structured_output) {
81 console.log(message.structured_output);
82 // { company_name: "Anthropic", founded_year: 2021, headquarters: "San Francisco, CA" }
83 }
84 }
85} catch (error) {
86 // A single-shot query() throws after yielding an error result, such as
87 // error_max_structured_output_retries; see the Error handling section.
88 console.error(`Session ended with an error: ${error}`);
89}
90```
91
92```python Python theme={null}
93import asyncio
94from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
95
96# Define the shape of data you want back
97schema = {
98 "type": "object",
99 "properties": {
100 "company_name": {"type": "string"},
101 "founded_year": {"type": "number"},
102 "headquarters": {"type": "string"},
68103 },
69 required: ["company_name"]
70 };
71
72 try {
73 for await (const message of query({
74 prompt: "Research Anthropic and provide key company information",
75 options: {
76 outputFormat: {
77 type: "json_schema",
78 schema: schema
79 }
80 }
81 })) {
82 // The result message contains structured_output with validated data
83 if (message.type === "result" && message.subtype === "success" && message.structured_output) {
84 console.log(message.structured_output);
85 // { company_name: "Anthropic", founded_year: 2021, headquarters: "San Francisco, CA" }
86 }
87 }
88 } catch (error) {
89 // A single-shot query() throws after yielding an error result, such as
90 // error_max_structured_output_retries; see the Error handling section.
91 console.error(`Session ended with an error: ${error}`);
104 "required": ["company_name"],
105}
106
107
108async def main():
109 try:
110 async for message in query(
111 prompt="Research Anthropic and provide key company information",
112 options=ClaudeAgentOptions(
113 output_format={"type": "json_schema", "schema": schema}
114 ),
115 ):
116 # The result message contains structured_output with validated data
117 if isinstance(message, ResultMessage) and message.structured_output:
118 print(message.structured_output)
119 # {'company_name': 'Anthropic', 'founded_year': 2021, 'headquarters': 'San Francisco, CA'}
120 except Exception as error:
121 # A single-shot query() raises after yielding an error result, such as
122 # error_max_structured_output_retries; see the Error handling section.
123 print(f"Session ended with an error: {error}")
124
125
126asyncio.run(main())
127```
128
129## Type-safe schemas with Zod and Pydantic
130
131Instead of writing JSON Schema by hand, you can use [Zod](https://zod.dev/) (TypeScript) or [Pydantic](https://docs.pydantic.dev/latest/) (Python) to define your schema. These libraries generate the JSON Schema for you and let you parse the response into a fully-typed object you can use throughout your codebase with autocomplete and type checking.
132
133The example below defines a schema for a feature implementation plan with a summary, list of steps (each with complexity level), and potential risks. The agent plans the feature and returns a typed `FeaturePlan` object. You can then access properties like `plan.summary` and iterate over `plan.steps` with full type safety.
134
135The SDK validates schemas with JSON Schema draft-07, so schemas that declare a newer version are rejected. Zod targets draft 2020-12 by default, so pass `target: "draft-7"` when converting your schema.
136
137```typescript TypeScript theme={null}
138import { z } from "zod";
139import { query } from "@anthropic-ai/claude-agent-sdk";
140
141// Define schema with Zod
142const FeaturePlan = z.object({
143 feature_name: z.string(),
144 summary: z.string(),
145 steps: z.array(
146 z.object({
147 step_number: z.number(),
148 description: z.string(),
149 estimated_complexity: z.enum(["low", "medium", "high"])
150 })
151 ),
152 risks: z.array(z.string())
153});
154
155type FeaturePlan = z.infer<typeof FeaturePlan>;
156
157// Convert to JSON Schema using the draft-07 target the SDK expects
158const schema = z.toJSONSchema(FeaturePlan, { target: "draft-7" });
159
160// Use in query
161try {
162 for await (const message of query({
163 prompt:
164 "Plan how to add dark mode support to a React app. Break it into implementation steps.",
165 options: {
166 outputFormat: {
167 type: "json_schema",
168 schema: schema
169 }
170 }
171 })) {
172 if (message.type === "result" && message.subtype === "success" && message.structured_output) {
173 // Validate and get fully typed result
174 const parsed = FeaturePlan.safeParse(message.structured_output);
175 if (parsed.success) {
176 const plan: FeaturePlan = parsed.data;
177 console.log(`Feature: ${plan.feature_name}`);
178 console.log(`Summary: ${plan.summary}`);
179 plan.steps.forEach((step) => {
180 console.log(`${step.step_number}. [${step.estimated_complexity}] ${step.description}`);
181 });
182 }
183 }
92184 }
93 ```
94
95 ```python Python theme={null}
96 import asyncio
97 from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
98
99 # Define the shape of data you want back
100 schema = {
101 "type": "object",
102 "properties": {
103 "company_name": {"type": "string"},
104 "founded_year": {"type": "number"},
105 "headquarters": {"type": "string"},
106 },
107 "required": ["company_name"],
108 }
109
110
111 async def main():
112 try:
113 async for message in query(
114 prompt="Research Anthropic and provide key company information",
115 options=ClaudeAgentOptions(
116 output_format={"type": "json_schema", "schema": schema}
117 ),
118 ):
119 # The result message contains structured_output with validated data
120 if isinstance(message, ResultMessage) and message.structured_output:
121 print(message.structured_output)
122 # {'company_name': 'Anthropic', 'founded_year': 2021, 'headquarters': 'San Francisco, CA'}
123 except Exception as error:
124 # A single-shot query() raises after yielding an error result, such as
125 # error_max_structured_output_retries; see the Error handling section.
126 print(f"Session ended with an error: {error}")
127
128
129 asyncio.run(main())
130 ```
131</CodeGroup>
132
133## Type-safe schemas with Zod and Pydantic
134
135Instead of writing JSON Schema by hand, you can use [Zod](https://zod.dev/) (TypeScript) or [Pydantic](https://docs.pydantic.dev/latest/) (Python) to define your schema. These libraries generate the JSON Schema for you and let you parse the response into a fully-typed object you can use throughout your codebase with autocomplete and type checking.
136
137The example below defines a schema for a feature implementation plan with a summary, list of steps (each with complexity level), and potential risks. The agent plans the feature and returns a typed `FeaturePlan` object. You can then access properties like `plan.summary` and iterate over `plan.steps` with full type safety.
138
139The SDK validates schemas with JSON Schema draft-07, so schemas that declare a newer version are rejected. Zod targets draft 2020-12 by default, so pass `target: "draft-7"` when converting your schema.
140
141<CodeGroup>
142 ```typescript TypeScript theme={null}
143 import { z } from "zod";
144 import { query } from "@anthropic-ai/claude-agent-sdk";
145
146 // Define schema with Zod
147 const FeaturePlan = z.object({
148 feature_name: z.string(),
149 summary: z.string(),
150 steps: z.array(
151 z.object({
152 step_number: z.number(),
153 description: z.string(),
154 estimated_complexity: z.enum(["low", "medium", "high"])
155 })
156 ),
157 risks: z.array(z.string())
158 });
159
160 type FeaturePlan = z.infer<typeof FeaturePlan>;
161
162 // Convert to JSON Schema using the draft-07 target the SDK expects
163 const schema = z.toJSONSchema(FeaturePlan, { target: "draft-7" });
164
165 // Use in query
166 try {
167 for await (const message of query({
168 prompt:
169 "Plan how to add dark mode support to a React app. Break it into implementation steps.",
170 options: {
171 outputFormat: {
172 type: "json_schema",
173 schema: schema
174 }
175 }
176 })) {
177 if (message.type === "result" && message.subtype === "success" && message.structured_output) {
178 // Validate and get fully typed result
179 const parsed = FeaturePlan.safeParse(message.structured_output);
180 if (parsed.success) {
181 const plan: FeaturePlan = parsed.data;
182 console.log(`Feature: ${plan.feature_name}`);
183 console.log(`Summary: ${plan.summary}`);
184 plan.steps.forEach((step) => {
185 console.log(`${step.step_number}. [${step.estimated_complexity}] ${step.description}`);
186 });
187 }
188 }
189 }
190 } catch (error) {
191 // A single-shot query() throws after yielding an error result, such as
192 // error_max_structured_output_retries; see the Error handling section.
193 console.error(`Session ended with an error: ${error}`);
194 }
195 ```
196
197 ```python Python theme={null}
198 import asyncio
199 from pydantic import BaseModel
200 from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
201
202
203 class Step(BaseModel):
204 step_number: int
205 description: str
206 estimated_complexity: str # 'low', 'medium', 'high'
207
208
209 class FeaturePlan(BaseModel):
210 feature_name: str
211 summary: str
212 steps: list[Step]
213 risks: list[str]
214
215
216 async def main():
217 try:
218 async for message in query(
219 prompt="Plan how to add dark mode support to a React app. Break it into implementation steps.",
220 options=ClaudeAgentOptions(
221 output_format={
222 "type": "json_schema",
223 "schema": FeaturePlan.model_json_schema(),
224 }
225 ),
226 ):
227 if isinstance(message, ResultMessage) and message.structured_output:
228 # Validate and get fully typed result
229 plan = FeaturePlan.model_validate(message.structured_output)
230 print(f"Feature: {plan.feature_name}")
231 print(f"Summary: {plan.summary}")
232 for step in plan.steps:
233 print(
234 f"{step.step_number}. [{step.estimated_complexity}] {step.description}"
235 )
236 except Exception as error:
237 # A single-shot query() raises after yielding an error result, such as
238 # error_max_structured_output_retries; see the Error handling section.
239 print(f"Session ended with an error: {error}")
240
241
242 asyncio.run(main())
243 ```
244</CodeGroup>
185} catch (error) {
186 // A single-shot query() throws after yielding an error result, such as
187 // error_max_structured_output_retries; see the Error handling section.
188 console.error(`Session ended with an error: ${error}`);
189}
190```
191
192```python Python theme={null}
193import asyncio
194from pydantic import BaseModel
195from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
196
197
198class Step(BaseModel):
199 step_number: int
200 description: str
201 estimated_complexity: str # 'low', 'medium', 'high'
202
203
204class FeaturePlan(BaseModel):
205 feature_name: str
206 summary: str
207 steps: list[Step]
208 risks: list[str]
209
210
211async def main():
212 try:
213 async for message in query(
214 prompt="Plan how to add dark mode support to a React app. Break it into implementation steps.",
215 options=ClaudeAgentOptions(
216 output_format={
217 "type": "json_schema",
218 "schema": FeaturePlan.model_json_schema(),
219 }
220 ),
221 ):
222 if isinstance(message, ResultMessage) and message.structured_output:
223 # Validate and get fully typed result
224 plan = FeaturePlan.model_validate(message.structured_output)
225 print(f"Feature: {plan.feature_name}")
226 print(f"Summary: {plan.summary}")
227 for step in plan.steps:
228 print(
229 f"{step.step_number}. [{step.estimated_complexity}] {step.description}"
230 )
231 except Exception as error:
232 # A single-shot query() raises after yielding an error result, such as
233 # error_max_structured_output_retries; see the Error handling section.
234 print(f"Session ended with an error: {error}")
235
236
237asyncio.run(main())
238```
245239
246240## Output format configuration
247241
from line 256
262256
263257The schema includes optional fields (`author` and `date`) since git blame information might not be available for all files. The agent fills in what it can find and omits the rest.
264258
265<CodeGroup>
266 ```typescript TypeScript theme={null}
267 import { query } from "@anthropic-ai/claude-agent-sdk";
268
269 // Define structure for TODO extraction
270 const todoSchema = {
271 type: "object",
272 properties: {
273 todos: {
274 type: "array",
275 items: {
276 type: "object",
277 properties: {
278 text: { type: "string" },
279 file: { type: "string" },
280 line: { type: "number" },
281 author: { type: "string" },
282 date: { type: "string" }
283 },
284 required: ["text", "file", "line"]
259```typescript TypeScript theme={null}
260import { query } from "@anthropic-ai/claude-agent-sdk";
261
262// Define structure for TODO extraction
263const todoSchema = {
264 type: "object",
265 properties: {
266 todos: {
267 type: "array",
268 items: {
269 type: "object",
270 properties: {
271 text: { type: "string" },
272 file: { type: "string" },
273 line: { type: "number" },
274 author: { type: "string" },
275 date: { type: "string" }
276 },
277 required: ["text", "file", "line"]
278 }
279 },
280 total_count: { type: "number" }
281 },
282 required: ["todos", "total_count"]
283};
284
285// Agent uses Grep to find TODOs, Bash to get git blame info
286try {
287 for await (const message of query({
288 prompt: "Find all TODO comments in this codebase and identify who added them",
289 options: {
290 outputFormat: {
291 type: "json_schema",
292 schema: todoSchema
293 }
294 }
295 })) {
296 if (message.type === "result" && message.subtype === "success" && message.structured_output) {
297 const data = message.structured_output as { total_count: number; todos: Array<{ file: string; line: number; text: string; author?: string; date?: string }> };
298 console.log(`Found ${data.total_count} TODOs`);
299 data.todos.forEach((todo) => {
300 console.log(`${todo.file}:${todo.line} - ${todo.text}`);
301 if (todo.author) {
302 console.log(` Added by ${todo.author} on ${todo.date}`);
285303 }
286 },
287 total_count: { type: "number" }
304 });
305 }
306 }
307} catch (error) {
308 // A single-shot query() throws after yielding an error result, such as
309 // error_max_structured_output_retries; see the Error handling section.
310 console.error(`Session ended with an error: ${error}`);
311}
312```
313
314```python Python theme={null}
315import asyncio
316from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
317
318# Define structure for TODO extraction
319todo_schema = {
320 "type": "object",
321 "properties": {
322 "todos": {
323 "type": "array",
324 "items": {
325 "type": "object",
326 "properties": {
327 "text": {"type": "string"},
328 "file": {"type": "string"},
329 "line": {"type": "number"},
330 "author": {"type": "string"},
331 "date": {"type": "string"},
332 },
333 "required": ["text", "file", "line"],
334 },
335 },
336 "total_count": {"type": "number"},
288337 },
289 required: ["todos", "total_count"]
290 };
291
292 // Agent uses Grep to find TODOs, Bash to get git blame info
293 try {
294 for await (const message of query({
295 prompt: "Find all TODO comments in this codebase and identify who added them",
296 options: {
297 outputFormat: {
298 type: "json_schema",
299 schema: todoSchema
300 }
301 }
302 })) {
303 if (message.type === "result" && message.subtype === "success" && message.structured_output) {
304 const data = message.structured_output as { total_count: number; todos: Array<{ file: string; line: number; text: string; author?: string; date?: string }> };
305 console.log(`Found ${data.total_count} TODOs`);
306 data.todos.forEach((todo) => {
307 console.log(`${todo.file}:${todo.line} - ${todo.text}`);
308 if (todo.author) {
309 console.log(` Added by ${todo.author} on ${todo.date}`);
310 }
311 });
312 }
313 }
314 } catch (error) {
315 // A single-shot query() throws after yielding an error result, such as
316 // error_max_structured_output_retries; see the Error handling section.
317 console.error(`Session ended with an error: ${error}`);
318 }
319 ```
320
321 ```python Python theme={null}
322 import asyncio
323 from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
324
325 # Define structure for TODO extraction
326 todo_schema = {
327 "type": "object",
328 "properties": {
329 "todos": {
330 "type": "array",
331 "items": {
332 "type": "object",
333 "properties": {
334 "text": {"type": "string"},
335 "file": {"type": "string"},
336 "line": {"type": "number"},
337 "author": {"type": "string"},
338 "date": {"type": "string"},
339 },
340 "required": ["text", "file", "line"],
341 },
342 },
343 "total_count": {"type": "number"},
344 },
345 "required": ["todos", "total_count"],
346 }
347
348
349 async def main():
350 # Agent uses Grep to find TODOs, Bash to get git blame info
351 try:
352 async for message in query(
353 prompt="Find all TODO comments in this codebase and identify who added them",
354 options=ClaudeAgentOptions(
355 output_format={"type": "json_schema", "schema": todo_schema}
356 ),
357 ):
358 if isinstance(message, ResultMessage) and message.structured_output:
359 data = message.structured_output
360 print(f"Found {data['total_count']} TODOs")
361 for todo in data["todos"]:
362 print(f"{todo['file']}:{todo['line']} - {todo['text']}")
363 if "author" in todo:
364 print(f" Added by {todo['author']} on {todo['date']}")
365 except Exception as error:
366 # A single-shot query() raises after yielding an error result, such as
367 # error_max_structured_output_retries; see the Error handling section.
368 print(f"Session ended with an error: {error}")
369
370
371 asyncio.run(main())
372 ```
373</CodeGroup>
338 "required": ["todos", "total_count"],
339}
340
341
342async def main():
343 # Agent uses Grep to find TODOs, Bash to get git blame info
344 try:
345 async for message in query(
346 prompt="Find all TODO comments in this codebase and identify who added them",
347 options=ClaudeAgentOptions(
348 output_format={"type": "json_schema", "schema": todo_schema}
349 ),
350 ):
351 if isinstance(message, ResultMessage) and message.structured_output:
352 data = message.structured_output
353 print(f"Found {data['total_count']} TODOs")
354 for todo in data["todos"]:
355 print(f"{todo['file']}:{todo['line']} - {todo['text']}")
356 if "author" in todo:
357 print(f" Added by {todo['author']} on {todo['date']}")
358 except Exception as error:
359 # A single-shot query() raises after yielding an error result, such as
360 # error_max_structured_output_retries; see the Error handling section.
361 print(f"Session ended with an error: {error}")
362
363
364asyncio.run(main())
365```
374366
375367## Error handling
376368
from line 377
385377
386378A result can also end with subtype `success` but no `structured_output` value, for example when the run completes without the agent producing a structured output. Treat that case as a failure as well. The troubleshooting entry [structured\_output is None but the result says success](/docs/en/agent-sdk/troubleshooting#structured_output-is-none-but-the-result-says-success) covers this case. The example below treats a result as successful only when the `subtype` is `success` and `structured_output` is present, and handles every other result as a failure:
387379
388<CodeGroup>
389 ```typescript TypeScript theme={null}
390 import { query } from "@anthropic-ai/claude-agent-sdk";
391
392 const contactSchema = {
393 type: "object",
394 properties: {
395 name: { type: "string" },
396 email: { type: "string" }
380```typescript TypeScript theme={null}
381import { query } from "@anthropic-ai/claude-agent-sdk";
382
383const contactSchema = {
384 type: "object",
385 properties: {
386 name: { type: "string" },
387 email: { type: "string" }
388 },
389 required: ["name"]
390};
391
392try {
393 for await (const msg of query({
394 prompt: "Extract contact info from the document",
395 options: {
396 outputFormat: {
397 type: "json_schema",
398 schema: contactSchema
399 }
400 }
401 })) {
402 if (msg.type === "result") {
403 if (msg.subtype === "success" && msg.structured_output) {
404 // Use the validated output
405 console.log(msg.structured_output);
406 } else if (msg.subtype === "error_max_structured_output_retries") {
407 console.error("Could not produce valid output");
408 } else {
409 console.error("Run ended without a structured output");
410 }
411 }
412 }
413} catch (error) {
414 // A single-shot query() throws after yielding an error result. If the
415 // failure was an error result, the error subtype branches above have
416 // already run; connection or process failures yield no result message.
417 console.log(`Session ended with an error: ${error}`);
418}
419```
420
421```python Python theme={null}
422import asyncio
423from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
424
425contact_schema = {
426 "type": "object",
427 "properties": {
428 "name": {"type": "string"},
429 "email": {"type": "string"},
397430 },
398 required: ["name"]
399 };
400
401 try {
402 for await (const msg of query({
403 prompt: "Extract contact info from the document",
404 options: {
405 outputFormat: {
406 type: "json_schema",
407 schema: contactSchema
408 }
409 }
410 })) {
411 if (msg.type === "result") {
412 if (msg.subtype === "success" && msg.structured_output) {
413 // Use the validated output
414 console.log(msg.structured_output);
415 } else if (msg.subtype === "error_max_structured_output_retries") {
416 console.error("Could not produce valid output");
417 } else {
418 console.error("Run ended without a structured output");
419 }
420 }
421 }
422 } catch (error) {
423 // A single-shot query() throws after yielding an error result. If the
424 // failure was an error result, the error subtype branches above have
425 // already run; connection or process failures yield no result message.
426 console.log(`Session ended with an error: ${error}`);
427 }
428 ```
429
430 ```python Python theme={null}
431 import asyncio
432 from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
433
434 contact_schema = {
435 "type": "object",
436 "properties": {
437 "name": {"type": "string"},
438 "email": {"type": "string"},
439 },
440 "required": ["name"],
441 }
442
443
444 async def main():
445 try:
446 async for message in query(
447 prompt="Extract contact info from the document",
448 options=ClaudeAgentOptions(
449 output_format={"type": "json_schema", "schema": contact_schema}
450 ),
451 ):
452 if isinstance(message, ResultMessage):
453 if message.subtype == "success" and message.structured_output:
454 # Use the validated output
455 print(message.structured_output)
456 elif message.subtype == "error_max_structured_output_retries":
457 print("Could not produce valid output")
458 else:
459 print("Run ended without a structured output")
460 except Exception as error:
461 # A single-shot query() raises after yielding an error result. If the
462 # failure was an error result, the error subtype branches above have
463 # already run; connection or process failures yield no result message.
464 print(f"Session ended with an error: {error}")
465
466
467 asyncio.run(main())
468 ```
469</CodeGroup>
431 "required": ["name"],
432}
433
434
435async def main():
436 try:
437 async for message in query(
438 prompt="Extract contact info from the document",
439 options=ClaudeAgentOptions(
440 output_format={"type": "json_schema", "schema": contact_schema}
441 ),
442 ):
443 if isinstance(message, ResultMessage):
444 if message.subtype == "success" and message.structured_output:
445 # Use the validated output
446 print(message.structured_output)
447 elif message.subtype == "error_max_structured_output_retries":
448 print("Could not produce valid output")
449 else:
450 print("Run ended without a structured output")
451 except Exception as error:
452 # A single-shot query() raises after yielding an error result. If the
453 # failure was an error result, the error subtype branches above have
454 # already run; connection or process failures yield no result message.
455 print(f"Session ended with an error: {error}")
456
457
458asyncio.run(main())
459```
470460
471461**Tips for avoiding errors:**
472462
473463
No line in this hunk matches that.