Claude API - Structured Outputs & Error Prevention Guide
Package
@anthropic-ai/sdk@0.71.2
Breaking Changes
Oct 2025 - Claude 3.5/3.7 models retired, Nov 2025 - Structured outputs beta
Last Updated
2026-01-09
What's New in v0.69.0+ (Nov 2025)
Major Features:
1. Structured Outputs (v0.69.0, Nov 14, 2025) - CRITICAL ⭐
Guaranteed JSON schema conformance
- Claude's responses strictly follow your JSON schema with two modes.
⚠️ ACCURACY CAVEAT
Structured outputs guarantee format compliance, NOT accuracy. Models can still hallucinate—you get "perfectly formatted incorrect answers." Always validate semantic correctness (see below).
JSON Outputs (
output_format
)
- For data extraction and formatting:
import
Anthropic
from
'@anthropic-ai/sdk'
;
const
anthropic
=
new
Anthropic
(
{
apiKey
:
process
.
env
.
ANTHROPIC_API_KEY
,
}
)
;
const
message
=
await
anthropic
.
messages
.
create
(
{
model
:
'claude-sonnet-4-5-20250929'
,
max_tokens
:
1024
,
messages
:
[
{
role
:
'user'
,
content
:
'Extract contact info: John Doe, john@example.com, 555-1234'
}
]
,
betas
:
[
'structured-outputs-2025-11-13'
]
,
output_format
:
{
type
:
'json_schema'
,
json_schema
:
{
name
:
'Contact'
,
strict
:
true
,
schema
:
{
type
:
'object'
,
properties
:
{
name
:
{
type
:
'string'
}
,
email
:
{
type
:
'string'
}
,
phone
:
{
type
:
'string'
}
}
,
required
:
[
'name'
,
'email'
,
'phone'
]
,
additionalProperties
:
false
}
}
}
}
)
;
// Guaranteed valid JSON matching schema
const
contact
=
JSON
.
parse
(
message
.
content
[
0
]
.
text
)
;
console
.
log
(
contact
.
name
)
;
// "John Doe"
Strict Tool Use (
strict: true
)
- For validated function parameters:
const
message
=
await
anthropic
.
messages
.
create
(
{
model
:
'claude-sonnet-4-5-20250929'
,
max_tokens
:
1024
,
messages
:
[
{
role
:
'user'
,
content
:
'Get weather for San Francisco'
}
]
,
betas
:
[
'structured-outputs-2025-11-13'
]
,
tools
:
[
{
name
:
'get_weather'
,
description
:
'Get current weather'
,
input_schema
:
{
type
:
'object'
,
properties
:
{
location
:
{
type
:
'string'
}
,
unit
:
{
type
:
'string'
,
enum
:
[
'celsius'
,
'fahrenheit'
]
}
}
,
required
:
[
'location'
]
,
additionalProperties
:
false
}
,
strict
:
true
// ← Guarantees schema compliance
}
]
}
)
;
Requirements:
Beta header
:
structured-outputs-2025-11-13
(via
betas
array)
Models
Claude Opus 4.5, Claude Sonnet 4.5, Claude Opus 4 (best models only)
SDK
v0.69.0+ required
Limitations:
❌ No recursive schemas
❌ No numerical constraints (
minimum
,
maximum
)
❌ Limited regex support (no backreferences/lookahead)
❌ Incompatible with citations and message prefilling
⚠️ Grammar compilation adds latency on first request (cached 24hrs)
Performance Characteristics:
First request
+200-500ms latency for grammar compilation
Subsequent requests
Normal latency (grammar cached for 24 hours)
Cache sharing
Only with IDENTICAL schemas (small changes = recompilation)
Pre-warming critical schemas:
// Pre-compile schemas during server startup
const
warmupMessage
=
await
anthropic
.
messages
.
create
(
{
model
:
'claude-sonnet-4-5-20250929'
,
max_tokens
:
10
,
messages
:
[
{
role
:
'user'
,
content
:
'warmup'
}
]
,
betas
:
[
'structured-outputs-2025-11-13'
]
,
output_format
:
{
type
:
'json_schema'
,
json_schema
:
YOUR_CRITICAL_SCHEMA
}
}
)
;
// Later requests use cached grammar
Semantic Validation (CRITICAL):
const
message
=
await
anthropic
.
messages
.
create
(
{
model
:
'claude-sonnet-4-5-20250929'
,
messages
:
[
{
role
:
'user'
,
content
:
'Extract contact: John Doe'
}
]
,
betas
:
[
'structured-outputs-2025-11-13'
]
,
output_format
:
{
type
:
'json_schema'
,
json_schema
:
contactSchema
}
}
)
;
const
contact
=
JSON
.
parse
(
message
.
content
[
0
]
.
text
)
;
// ✅ Format is guaranteed valid
// ❌ Content may be hallucinated
// ALWAYS validate semantic correctness
if
(
!
isValidEmail
(
contact
.
email
)
)
{
throw
new
Error
(
'Hallucinated email detected'
)
;
}
if
(
contact
.
age
<
0
||
contact
.
age
>
120
)
{
throw
new
Error
(
'Implausible age value'
)
;
}
When to Use:
Data extraction from unstructured text
API response formatting
Agentic workflows requiring validated tool inputs
Eliminating JSON parse errors
⚠️ SDK v0.71.1+ Deprecation
Direct
.parsed
property access is deprecated. Check SDK docs for updated API.
2. Model Changes (Oct 2025) - BREAKING
Retired (return errors):
❌ Claude 3.5 Sonnet (all versions)
❌ Claude 3.7 Sonnet - DEPRECATED (Oct 28, 2025)
Active Models (Jan 2026):
Model
ID
Context
Best For
Cost (per MTok)
Claude Opus 4.5
claude-opus-4-5-20251101
200k
Flagship - best reasoning, coding, agents
$5/$25 (in/out)
Claude Sonnet 4.5
claude-sonnet-4-5-20250929
200k
Balanced performance
$3/$15 (in/out)
Claude Opus 4
claude-opus-4-20250514
200k
High capability
$15/$75
Claude Haiku 4.5
claude-haiku-4-5-20250929
200k
Near-frontier, fast
$1/$5
Note
Claude 3.x models (3.5 Sonnet, 3.7 Sonnet, etc.) are deprecated. Use Claude 4.x+ models.
3. Context Management (Oct 28, 2025)
Clear Thinking Blocks
- Automatic thinking block cleanup:
const
message
=
await
anthropic
.
messages
.
create
(
{
model
:
'claude-sonnet-4-5-20250929'
,
max_tokens
:
4096
,
messages
:
[
{
role
:
'user'
,
content
:
'Solve complex problem'
}
]
,
betas
:
[
'clear_thinking_20251015'
]
}
)
;
// Thinking blocks automatically managed
4. Agent Skills API (Oct 16, 2025)
Pre-built skills for Office files (PowerPoint, Excel, Word, PDF):
Prompt caching does NOT work for Claude 4 family on AWS Bedrock (works for Claude 3.7 Sonnet only). Use direct Anthropic API for Claude 4 caching support. (
GitHub Issue #1347
)
Tool Use (Function Calling)
CRITICAL Patterns:
Strict Tool Use
(with structured outputs):
const
message
=
await
anthropic
.
messages
.
create
(
{
model
:
'claude-sonnet-4-5-20250929'
,
max_tokens
:
1024
,
betas
:
[
'structured-outputs-2025-11-13'
]
,
tools
:
[
{
name
:
'get_weather'
,
description
:
'Get weather data'
,
input_schema
:
{
type
:
'object'
,
properties
:
{
location
:
{
type
:
'string'
}
,
unit
:
{
type
:
'string'
,
enum
:
[
'celsius'
,
'fahrenheit'
]
}
}
,
required
:
[
'location'
]
,
additionalProperties
:
false
}
,
strict
:
true
// ← Guarantees schema compliance
}
]
,
messages
:
[
{
role
:
'user'
,
content
:
'Weather in NYC?'
}
]
}
)
;
Tool Result Pattern
-
tool_use_id
MUST match:
const
toolResults
=
[
]
;
for
(
const
block
of
response
.
content
)
{
if
(
block
.
type
===
'tool_use'
)
{
const
result
=
await
executeToolFunction
(
block
.
name
,
block
.
input
)
;
toolResults
.
push
(
{
type
:
'tool_result'
,
tool_use_id
:
block
.
id
,
// ← MUST match tool_use block id
content
:
JSON
.
stringify
(
result
)
,
}
)
;
}
}
messages
.
push
(
{
role
:
'user'
,
content
:
toolResults
,
}
)
;
Error Handling
- Handle tool execution failures:
try
{
const
result
=
await
executeToolFunction
(
block
.
name
,
block
.
input
)
;
toolResults
.
push
(
{
type
:
'tool_result'
,
tool_use_id
:
block
.
id
,
content
:
JSON
.
stringify
(
result
)
,
}
)
;
}
catch
(
error
)
{
// Return error to Claude for handling
toolResults
.
push
(
{
type
:
'tool_result'
,
tool_use_id
:
block
.
id
,
is_error
:
true
,
content
:
`
Tool execution failed:
${
error
.
message
}
`
,
}
)
;
}
Content Sanitization
- Handle Unicode edge cases:
// U+2028 (LINE SEPARATOR) and U+2029 (PARAGRAPH SEPARATOR) cause JSON parse failures
function
sanitizeToolResult
(
content
:
string
)
:
string
{
return
content
.
replace
(
/
\u2028
/
g
,
'\n'
)
// LINE SEPARATOR → newline
.
replace
(
/
\u2029
/
g
,
'\n'
)
;
// PARAGRAPH SEPARATOR → newline
}
const
toolResult
=
{
type
:
'tool_result'
,
tool_use_id
:
block
.
id
,
content
:
sanitizeToolResult
(
result
)
// Sanitize before sending
}
;
(
GitHub Issue #882
)
Vision (Image Understanding)
CRITICAL Rules:
Formats
JPEG, PNG, WebP, GIF (non-animated)
Max size
5MB per image
Base64 overhead
~33% size increase
Context impact
Images count toward token limit
Caching
Consider for repeated image analysis
Format validation
- Check before encoding:
const
validFormats
=
[
'image/jpeg'
,
'image/png'
,
'image/webp'
,
'image/gif'
]
;
if
(
!
validFormats
.
includes
(
mimeType
)
)
{
throw
new
Error
(
`
Unsupported format:
${
mimeType
}
`
)
;
}
Extended Thinking Mode
⚠️ Model Compatibility:
❌ Claude 3.7 Sonnet - DEPRECATED (Oct 28, 2025)
❌ Claude 3.5 Sonnet - RETIRED (not supported)
✅ Claude Opus 4.5 - Extended thinking supported (flagship)
✅ Claude Sonnet 4.5 - Extended thinking supported
✅ Claude Opus 4 - Extended thinking supported
CRITICAL:
Thinking blocks are NOT cacheable
Requires higher
max_tokens
(thinking consumes tokens)
Check model before expecting thinking blocks
Rate Limits
CRITICAL Pattern
- Respect
retry-after
header with exponential backoff:
async
function
makeRequestWithRetry
(
requestFn
:
(
)
=>
Promise
<
any
>
,
maxRetries
=
3
,
baseDelay
=
1000
)
:
Promise
<
any
>
{
for
(
let
attempt
=
0
;
attempt
<
maxRetries
;
attempt
++
)
{
try
{
return
await
requestFn
(
)
;
}
catch
(
error
)
{
if
(
error
.
status
===
429
)
{
// CRITICAL: Use retry-after header if present
const
retryAfter
=
error
.
response
?.
headers
?.
[
'retry-after'
]
;
const
delay
=
retryAfter
?
parseInt
(
retryAfter
)
*
1000
:
baseDelay
*
Math
.
pow
(
2
,
attempt
)
;
console
.
warn
(
`
Rate limited. Retrying in
${
delay
}
ms...
`
)
;
await
new
Promise
(
resolve
=>
setTimeout
(
resolve
,
delay
)
)
;
}
else
{
throw
error
;
}
}
}
throw
new
Error
(
'Max retries exceeded'
)
;
}
Rate limit headers:
anthropic-ratelimit-requests-limit
- Total RPM allowed
anthropic-ratelimit-requests-remaining
- Remaining requests
anthropic-ratelimit-requests-reset
- Reset timestamp
Error Handling
Common Error Codes:
Status
Error Type
Cause
Solution
400
invalid_request_error
Bad parameters
Validate request body
401
authentication_error
Invalid API key
Check env variable
403
permission_error
No access to feature
Check account tier
404
not_found_error
Invalid endpoint
Check API version
429
rate_limit_error
Too many requests
Implement retry logic
500
api_error
Internal error
Retry with backoff
529
overloaded_error
System overloaded
Retry later
CRITICAL:
Streaming errors occur AFTER initial 200 response
Always implement error event listeners for streams
Respect
retry-after
header on 429 errors
Have fallback strategies for critical operations
Known Issues Prevention
This skill prevents
16
documented issues:
Issue #1: Rate Limit 429 Errors Without Backoff
Error
:
429 Too Many Requests: Number of request tokens has exceeded your per-minute rate limit
Source
:
https://docs.claude.com/en/api/errors
Why It Happens
Exceeding RPM, TPM, or daily token limits
Prevention
Implement exponential backoff with
retry-after
header respect
Issue #2: Streaming SSE Parsing Errors
Error
Incomplete chunks, malformed SSE events
Source
Common SDK issue (GitHub #323)
Why It Happens
Network interruptions, improper event parsing
Prevention
Use SDK stream helpers, implement error event listeners