The Opus 5 migration guide is honest about the easy part: change the model ID and you're done.
model = "claude-opus-4-8" # before
model = "claude-opus-5" # after
That's the whole required edit. The trouble is the two behavior changes that ride along — the kind a find-and-replace across your codebase won't flag, and that surface as either a truncated answer or an outright 400. Both are cheap to fix once you know they're there.
Breaking change 1: thinking is on by default#
On Opus 4.8, a plain request ran without thinking unless you explicitly set thinking: {"type": "adaptive"}. On Opus 5, that same request thinks by default — the model decides when and how much to think each turn, and effort is the dial for how deep.
The trap is max_tokens. It's a hard limit on total output — thinking tokens plus visible text. A max_tokens you tuned for a text-only workload on 4.8 now has to cover thinking too, so a value that was comfortable can start truncating the visible answer.
Fix: revisit max_tokens on any workload that previously ran without thinking. Raise it, and for xhigh/max effort give it real headroom — start around 64k and tune down.
Breaking change 2: you can't disable thinking at high effort#
This is the one that returns a hard error. On Opus 5:
# 400 error on Opus 5
client.messages.create(
model="claude-opus-5",
max_tokens=8192,
output_config={"effort": "xhigh"},
thinking={"type": "disabled"}, # rejected at xhigh / max
messages=[...],
)
thinking: {"type": "disabled"} is only accepted when effort is high or below. Combine it with xhigh or max and the request 400s. On Opus 4.8 the two settings were independent, so any code that disabled thinking while pushing effort high is now broken.
Fix, pick one:
- Keep thinking disabled → set
efforttohighor below. - Keep the high effort level → remove the
thinkingfield (thinking is on by default anyway).
And a recommendation from the docs worth heeding: prefer keeping thinking on. With it disabled, Opus 5 can occasionally emit a tool call as plain text instead of a proper tool_use block, or leak internal XML tags into its visible output. If your goal was cost, lower the effort level instead — it's cleaner and cheaper.
Two behavior shifts that aren't errors — but will surprise you#
Neither of these throws, but both change output you may be asserting on:
- Opus 5 verifies its own work. If you carried over instructions like "include a final verification step" or "use a subagent to verify," delete them — they cause over-verification on Opus 5. The model already double-checks.
- Responses run longer by default, and it narrates progress more in agentic sessions. If you need terse output, prompt for it explicitly;
effortwon't reliably shorten the visible answer.
The upside you get for free#
Two changes reward you for touching nothing:
- The prompt-cache minimum drops to 512 tokens (from 1,024 on 4.8). Short prompts that couldn't cache before now can, with zero code changes — a quiet cost win.
- Mid-conversation tool changes (beta header
mid-conversation-tool-changes-2026-07-01) let you add or remove tools between turns while preserving the prompt cache — the API-level version of the progressive tool disclosure the MCP world has been chasing.
Migration checklist#
- Swap the model ID →
claude-opus-5. - Raise
max_tokenson anything that ran without thinking on 4.8. - Grep for
"type": "disabled"paired witheffortxhigh/max→ fix the pairing. - Delete carried-over "verify your work" instructions.
- Run an effort sweep and re-baseline
max_tokensand cost per completed task.
Five steps, one afternoon. The model ID is the migration; the two breaking changes are the part that actually needs your eyes.



