
Your Claude budget_tokens Code Is Broken on Opus 5 — Migrate to adaptive + effort in 3 Lines
Chris Harper
2 min read
Jul 31, 2026 · 12:13 UTC
Claude Opus 5 (launched July 24) rejects thinking: {type: "enabled", budget_tokens: N} with a 400 error — three lines migrate any existing code to the new adaptive mode with output_config.effort.
If you're calling Claude's thinking API today with budget_tokens, your code breaks the moment you switch to Opus 5 (or any 4.7+ model). Here's the exact migration.
What broke
# 400 error on Opus 5 and all models >= 4.7:
client.messages.create(
model="claude-opus-5",
max_tokens=16000,
thinking={"type": "enabled", "budget_tokens": 10000}, # rejected
messages=[...]
)
The fix
# Correct pattern for Opus 5 and all 4.7+ models:
client.messages.create(
model="claude-opus-5",
max_tokens=16000,
thinking={"type": "adaptive"}, # or omit entirely on Opus 5
output_config={"effort": "high"}, # low | medium | high | xhigh | max
messages=[...]
)
On Claude Opus 5, Sonnet 5, Fable 5, and Mythos 5, thinking is on by default — you can omit the thinking field entirely if high effort works for your use case.
Migration table
| Model | Thinking default | budget_tokens? | effort? |
|---|---|---|---|
| Opus 5, Sonnet 5, Fable 5, Mythos 5 | On by default | 400 error | Yes |
| Opus 4.8, 4.7 | Off | 400 error | Yes (needed to enable) |
| Sonnet 4.6, Opus 4.6 | Off | Deprecated but accepted | Yes (preferred) |
| Haiku 4.5, Sonnet 4.5 | Off | Required (type: "enabled" only) | No |
| Opus 4.5 | Off | Required | Yes |
Turn thinking off on Opus 5 (for fast, cheap responses)
client.messages.create(
model="claude-opus-5",
max_tokens=4096,
thinking={"type": "disabled"},
output_config={"effort": "low"}, # "disabled" + "xhigh"/"max" = 400 error
messages=[...]
)
Cannot combine disabled with xhigh or max effort — that returns 400. On Fable 5 and Mythos 5, disabled is rejected entirely.
Streaming (required when max_tokens > 21,333 on Opus 5)
with client.messages.stream(
model="claude-opus-5",
max_tokens=64000,
output_config={"effort": "max"},
messages=[...]
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
response = stream.get_final_message()
To see thinking tokens alongside the response, add thinking={"type": "adaptive", "display": "summarized"} — thinking streams as thinking_delta events before text starts.
Sources: Thinking — Claude Platform Docs · Extended thinking (legacy) — Claude Docs · What's new in Claude Opus 5 — Claude Docs