Uncategorized

Claude Opus 5.5: Breaking Changes and What It Really Costs

Claude Opus 5.5: Breaking Changes and What It Really Costs

Anthropic released Claude Opus 5.5 on 22 September 2026 at $4 per million input tokens and $20 per million output, down from Opus 5’s $5 and $25. This post is for developers who already call Opus 5 (or an older Opus) through the API and want to know two things before they switch: which requests will start failing, and what the move actually saves on their workload. Changing the model string is not enough on its own. Four request shapes that Opus 5 accepts return a 400 on Claude Opus 5.5, and one silent default change alters how hard the model thinks on every call that does not set it. Below you will find each breaking change with before-and-after code, a grep that finds them in a codebase, and cost-per-task arithmetic on three workloads using the launch-day price table.

Sources and Prices, Read on Launch Day

Every price and version claim in this post was read on the day of release. Pricing changes faster than anything else here, so treat the numbers as a dated snapshot.

Read 2026-09-22 (Claude Opus 5.5 launch day)
Pricing        https://platform.claude.com/docs/en/about-claude/pricing
Models         https://platform.claude.com/docs/en/models/overview
What's new     https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5
Migration      https://platform.claude.com/docs/en/models/opus-5-5/migration-guide
Announcement   https://www.anthropic.com/claude-opus-5-5
SDK used for the code below: anthropic 1.8.0 (Python), Python 3.14
USD per million tokens, Claude API list price, no volume discount
Next scheduled re-read: 2026-12-22

The code samples were run against SDK 1.8.0 with a mocked transport to confirm the exact request bodies they send. They were not run against the live API, so no latency or token-count figures appear anywhere in this post. Every cost number is arithmetic on published prices, with the assumptions stated.

What Is Claude Opus 5.5?

Claude Opus 5.5 is Anthropic’s Opus-tier model for long-running agentic coding and knowledge work, released 22 September 2026 as the successor to Claude Opus 5. It keeps the 1M token context window and 128K max output, costs 20% less per token, and always runs with adaptive thinking, which the effort parameter now controls.

Here is how it sits next to the models you are most likely choosing between. Prices come from the pricing page read on launch day; the other rows come from the models overview.

Claude Opus 5.5Claude Opus 5Claude Fable 5.1Claude Sonnet 5
API IDclaude-opus-5-5claude-opus-5claude-fable-5-1claude-sonnet-5
Input / output per MTok$4 / $20$5 / $25$10 / $50$2 / $10
Cache read per MTok$0.20$0.50$0.25$0.20
5-minute cache write per MTok$5$6.25$12.50$2.50
Batch input / output per MTok$2 / $10$2.50 / $12.50$5 / $25$1 / $5
Fast mode input / output per MTok$8 / $40$10 / $50n/an/a
ThinkingAlways onOn by default, can be disabled at high or belowAlways onAdaptive
Default effortmediumhighhighhigh
Context / max output1M / 128K1M / 128K1M / 128K1M / 128K

Notably, the cache read rate dropped further than the headline price. Opus 5.5 bills cache hits at 0.05x its base input price, where most models use 0.1x. As a result, cache reads cost 60% less than on Opus 5, and that matters a great deal for agent loops, as the cost section shows.

Availability is broad from day one: the Claude API, Amazon Bedrock (as anthropic.claude-opus-5-5), Claude Platform on AWS, Google Cloud, and Microsoft Foundry (all as claude-opus-5-5). Fast mode is Claude API only.

Does Claude Opus 5.5 Outperform Fable 5.1?

On Anthropic’s own published benchmarks, yes, on several of them. These are vendor-reported figures from the announcement, not independent measurements, and each ran with adaptive thinking at max effort.

Benchmark (vendor-reported)Opus 5.5Fable 5.1Opus 5
Terminal-Bench 4.066.4%55.8%52.3%
CursorBench 4.057.8%51.8%46.6%
FrontierCode v1.154.4%50.3%48.0%
AutomationBench40.0%31.4%26.9%
OSWorld 2.081.8%80.7%74.0%
Humanity’s Last Exam (with tools)67.7%65.6%63.6%

Anthropic adds a caveat worth taking seriously: “At these levels of capability we’ve found that benchmark margins have become a less reliable guide to real-world differences.” In practice, that means the table tells you Opus 5.5 is worth evaluating before you pay Fable prices. It does not tell you it wins on your workload. Your own eval set decides that.

The Four Breaking Changes in Claude Opus 5.5

These four request shapes work on Opus 5 and return a 400 invalid_request_error on Claude Opus 5.5. Each one is covered below with its fix.

  1. thinking: {"type": "disabled"} or {"type": "enabled", "budget_tokens": N}
  2. tool_choice of type any or tool (forced tool use)
  3. Replaying thinking blocks after editing the conversation’s prefix (enforced for accounts created on or after 31 August 2026)
  4. The computer_20251124 tool on the Claude API and Google Cloud

Before touching any code, find the call sites. This grep is deliberately noisy, because a false positive costs a second of reading while a miss costs a production 400.

# Find request shapes that break on Claude Opus 5.5
grep -rnE '"disabled"|budget_tokens|type"?:\s*"(any|tool)"|computer_20251124|content\[0\]' \
  --include='*.py' --include='*.ts' --include='*.js' .

# Output on a small fixture with one of each:
# src/client.ts:1:const r = await client.messages.create({ model: "claude-opus-5", tool_choice: { type: "any" }, tools, messages });
# src/agent.py:2:resp = client.messages.create(model=MODEL, thinking={"type": "disabled"}, max_tokens=1024, messages=m)
# src/agent.py:3:resp = client.messages.create(model=MODEL, tool_choice={"type": "tool", "name": "save"}, tools=t, messages=m)
# src/agent.py:4:tools = [{"type": "computer_20251124", "name": "computer"}]
# src/agent.py:5:thinking = {"type": "enabled", "budget_tokens": 8000}
# src/agent.py:6:first = resp.content[0].text

The last pattern, content[0], is not a 400. However, it is the bug that shows up right after you fix the 400s, which the next section explains.

Breaking Change 1: Thinking Can’t Be Disabled

On Opus 5, you could turn thinking off at effort high or below, a common choice on latency-sensitive routes. On Claude Opus 5.5, thinking is always on. Both the disabled form and the older budget form fail with a message that tells you the fix:

"thinking.type.disabled" is not supported for this model. Use "thinking.type.adaptive" and "output_config.effort" to control thinking behavior.

Consequently, effort becomes the only control for thinking depth, latency and cost. Where you disabled thinking to save tokens, remove the thinking field and use low effort instead. The helper below is what a migrated call looks like, with the two checks that most migrations forget.

import anthropic

client = anthropic.Anthropic()


def ask(prompt: str, effort: str = "high") -> str:
    response = client.beta.messages.create(
        model="claude-opus-5-5",
        max_tokens=16000,
        output_config={"effort": effort},  # set it: the default is now medium
        fallbacks="default",  # retry declined requests on Anthropic's recommended model
        betas=["server-side-fallback-2026-07-01"],
        messages=[{"role": "user", "content": prompt}],
    )
    if response.stop_reason == "refusal":
        category = response.stop_details.category if response.stop_details else None
        raise RuntimeError(f"Every model in the fallback chain declined: {category}")
    if response.stop_reason == "max_tokens":
        raise RuntimeError("Hit max_tokens; thinking counts toward it, raise the limit")
    # Thinking blocks come first, so select text by type and never by position
    return "".join(block.text for block in response.content if block.type == "text")

Why each piece is there: every response can now start with one or more thinking blocks, and under the default display: "omitted" their text is empty. Code that reads response.content[0].text therefore gets a thinking block instead of the answer. Also, thinking tokens count against max_tokens even when you never see them, so a limit sized for a thinking-off route will truncate replies. The refusal check exists because Opus 5.5 runs broader safety classifiers than Opus 5: bio and reasoning_extraction join cyber as refusal categories.

One more follow-up if you ran with thinking disabled. Delete any prompt line that asks the model to write its reasoning into the answer as a stand-in for thinking. According to the migration guide, a prompt that pushes the model to reproduce its internal reasoning can now be declined with the reasoning_extraction category. If you want to see the reasoning, read it from display: "summarized" thinking blocks. For the background on how adaptive thinking replaced fixed budgets, see our guide to Claude extended thinking.

Breaking Change 2: Forced Tool Use Returns a 400

Forcing a tool call with tool_choice: {"type": "tool", "name": ...} was the standard trick for getting JSON out of Claude. On Claude Opus 5.5 it fails on the Messages API, the Batches API and the token-counting endpoint:

tool_choice: type "tool" and "any" are not supported for this model.

The right fix depends on why you forced the call. If the tool existed only to get structured JSON back, drop the tool and use structured outputs, which constrain the response itself.

from pydantic import BaseModel


class Invoice(BaseModel):
    vendor: str
    total_cents: int
    currency: str


def extract_invoice(text: str) -> Invoice:
    response = client.messages.parse(
        model="claude-opus-5-5",
        max_tokens=4096,
        output_config={"effort": "low"},  # extraction rarely needs deep thinking
        output_format=Invoice,
        messages=[{"role": "user", "content": f"Extract the invoice fields.\n\n{text}"}],
    )
    if response.parsed_output is None:
        raise ValueError(f"No invoice parsed, stop_reason={response.stop_reason}")
    return response.parsed_output

The SDK converts the Pydantic model into a JSON schema with additionalProperties: false and validates the reply against it, so parsed_output is a typed Invoice rather than a dict you have to check.

On the other hand, if the tool call is a real action in an agent loop, keep tool_choice on auto, mark the tool strict, and name the tool in the prompt. Because auto does not guarantee a call, you also need to check for one.

RECORD_INVOICE = {
    "name": "record_invoice",
    "description": "Save the vendor, total and currency of one invoice.",
    "strict": True,  # arguments are guaranteed to match input_schema
    "input_schema": {
        "type": "object",
        "properties": {
            "vendor": {"type": "string"},
            "total_cents": {"type": "integer"},
            "currency": {"type": "string"},
        },
        "required": ["vendor", "total_cents", "currency"],
        "additionalProperties": False,
    },
}


def record_invoice_call(text: str, attempts: int = 2) -> dict:
    for _ in range(attempts):
        response = client.messages.create(
            model="claude-opus-5-5",
            max_tokens=4096,
            tools=[RECORD_INVOICE],
            tool_choice={"type": "auto"},
            messages=[{
                "role": "user",
                "content": f"Call record_invoice with the fields of this invoice.\n\n{text}",
            }],
        )
        for block in response.content:
            if block.type == "tool_use" and block.name == "record_invoice":
                return block.input
    raise RuntimeError(f"No record_invoice call after {attempts} attempts")

In short: structured outputs for data, strict auto tools for actions. If you want the full tool-use loop this plugs into, our Claude tool use guide walks through it.

Breaking Change 3: Thinking Blocks Are Tied to the Conversation

This one breaks harnesses, not individual requests. Every thinking block now records which model produced it and what came before it. For accounts created on or after 31 August 2026, 00:00 UTC, replaying a thinking block after you changed the system prompt, the tools array, or any earlier message returns a 400 by default. Older accounts are exempt unless they opt in.

In practice, three common habits trip it:

  • Injecting a per-turn reminder into the conversation and deleting it on the next turn
  • Adding or removing tools partway through a session
  • Client-side compaction that summarizes old turns but replays newer turns with their thinking blocks

The fix is to keep the conversation append-only. Change instructions with a mid-conversation system message instead of editing the top-level prompt, declare the full tool set up front, and use server-side compaction. If you cannot restructure yet, the thinking-binding-controls-2026-08-01 beta lets you set thinking.block_binding.prefix_mismatch_behavior to "drop_block", which drops the stale blocks instead of failing.

Model routing is affected too. Opus 5.5 reads thinking blocks from Opus 5 and earlier Opus, Sonnet and Haiku models, so moving a conversation onto it keeps the reasoning. Going the other way, only Fable 5.1 and Mythos 5.1 on the Claude API read Opus 5.5’s blocks. A fallback from Opus 5.5 to Opus 5 therefore continues without the earlier reasoning. The request still succeeds and the dropped blocks aren’t billed, but the model loses context it had. Notably, an append-only harness is also a better cached harness, so this change pays for itself in prompt caching hit rate.

Breaking Change 4: The Old Computer Use Tool Is Rejected

On the Claude API and Google Cloud, Claude Opus 5.5 accepts computer use only as the computer_toolset_20260801 toolset. A computer_20251124 entry fails with 'claude-opus-5-5' does not support tool types: computer_20251124. On Amazon Bedrock the older tool keeps working.

The request change is small, but the agent loop change is not. The toolset entry takes no name and no display size, and the beta header goes away. More importantly, each action now arrives as its own tool_use block whose name is the action (screenshotleft_clicktype), several can arrive per turn, and every tool_result must echo "toolset_name": "computer". Opus 5 accepts both forms, so make and test this change on Opus 5 before you switch models. Our Claude computer use post covers the loop this replaces.

The Silent Change: Default Effort Is Now Medium

Nothing fails here, which is exactly why it deserves its own section. A request that omits effort ran at high on Opus 5 and runs at medium on Claude Opus 5.5. Additionally, the what’s-new page says Opus 5.5 “tends to think more per turn than Claude Opus 5” at a given effort level, most of all at xhigh and max.

So a pure model-ID swap changes two variables at once: the model and the effort. If quality moves after the switch, you won’t know which one moved it. Set effort explicitly on every route, and re-run the sweep rather than carrying the old setting over. Anthropic’s prompting guide says that in their testing Opus 5.5 at medium “matches or exceeds Claude Opus 5 at high on coding and knowledge-work evaluations”. Treat that as a hypothesis for your eval set to confirm or reject, not a setting to copy.

Text Between Tool Calls Moves Into Thinking Blocks

This is the other change that fails no request. On Opus 5, the short notes the model writes between tool calls (“found the failing test, reading the fixture next”) come back as text blocks. On Claude Opus 5.5 they come back as progress-update thinking blocks, and under the default display their text is empty. An interface that streams those notes to users goes quiet for the whole agent turn.

To get them back, stream with display: "updates", which returns the progress notes while keeping the reasoning hidden:

def run_turn(messages: list, tools: list) -> list:
    # Streaming is required here: the SDK refuses a 64K max_tokens request without it
    with client.beta.messages.stream(
        model="claude-opus-5-5",
        max_tokens=64000,
        thinking={"type": "adaptive", "display": "updates"},
        betas=["thinking-display-updates-2026-08-18"],
        tools=tools,
        messages=messages,
    ) as stream:
        for event in stream:
            if event.type == "content_block_delta" and event.delta.type == "thinking_delta":
                print(event.delta.thinking, end="", flush=True)  # progress note for the user
        message = stream.get_final_message()
    # Append the full content, thinking blocks included, unmodified
    messages.append({"role": "assistant", "content": message.content})
    return messages

The streaming requirement is not a style choice. Calling client.beta.messages.create with max_tokens=64000 raises ValueError: Streaming is required for operations that may take longer than 10 minutes in SDK 1.8.0 before any request is sent. Appending message.content whole, rather than extracting the text, keeps the thinking blocks intact for the next turn, which Breaking Change 3 depends on.

What Claude Opus 5.5 Costs per Task

Anthropic’s headline says Opus 5.5 is “40% less than Opus 5 on typical workloads”. The per-token price only accounts for 20% of that. The rest has to come from cheaper cache reads and from the model producing fewer tokens for the same task. The script below separates those effects on three workloads, using the launch-day prices.

"""Cost per task on Claude Opus 5.5 vs Opus 5, Fable 5.1 and Sonnet 5.

Prices: USD per million tokens, Claude API list prices read 2026-09-22 from
https://platform.claude.com/docs/en/about-claude/pricing
"""
from dataclasses import dataclass


@dataclass(frozen=True)
class Price:
    input: float
    cache_write_5m: float
    cache_read: float
    output: float


PRICES = {
    "Claude Opus 5.5": Price(4.00, 5.00, 0.20, 20.00),
    "Claude Opus 5": Price(5.00, 6.25, 0.50, 25.00),
    "Claude Fable 5.1": Price(10.00, 12.50, 0.25, 50.00),
    "Claude Sonnet 5": Price(2.00, 2.50, 0.20, 10.00),
}


@dataclass(frozen=True)
class Workload:
    name: str
    uncached_in: int   # tokens billed at the base input rate
    cache_write: int   # tokens written to the 5-minute cache
    cache_read: int    # tokens read from cache
    output: int        # visible output plus thinking tokens
    runs: int          # how many times the task runs
    batch: bool = False


WORKLOADS = [
    # One analysis call, nothing cached: 8k in, 2k out, 10,000 calls
    Workload("single call", 8_000, 0, 0, 2_000, 10_000),
    # One agentic coding task: 40 turns, ~150k context per turn,
    # 5k new tokens per turn, the rest read from cache, 4k out per turn
    Workload("agent task", 0, 40 * 5_000, 40 * 145_000, 40 * 4_000, 1),
    # Batch extraction: 3k in, 500 out per document, 10,000 documents
    Workload("batch extract", 3_000, 0, 0, 500, 10_000, batch=True),
]


def cost(p: Price, w: Workload, output_scale: float = 1.0) -> float:
    per_run = (
        w.uncached_in * p.input
        + w.cache_write * p.cache_write_5m
        + w.cache_read * p.cache_read
        + w.output * output_scale * p.output
    ) / 1_000_000
    if w.batch:
        per_run *= 0.5  # Batch API: 50% off input and output
    return per_run * w.runs


if __name__ == "__main__":
    base = "Claude Opus 5"
    for w in WORKLOADS:
        print(f"\n{w.name} (x{w.runs:,})")
        ref = cost(PRICES[base], w)
        for model, p in PRICES.items():
            c = cost(p, w)
            print(f"  {model:<17} ${c:>10,.2f}   {c / ref - 1:+.0%} vs {base}")

    print("\nagent task on Opus 5.5 if it emits fewer output tokens than Opus 5")
    agent = WORKLOADS[1]
    ref = cost(PRICES[base], agent)
    for cut in (0.0, 0.25, 0.40, 0.50):
        c = cost(PRICES["Claude Opus 5.5"], agent, output_scale=1 - cut)
        print(f"  output -{cut:>3.0%}   ${c:,.2f}   {c / ref - 1:+.0%} vs {base}")

Running python3 opus_cost.py prints:

single call (x10,000)
  Claude Opus 5.5   $    720.00   -20% vs Claude Opus 5
  Claude Opus 5     $    900.00   +0% vs Claude Opus 5
  Claude Fable 5.1  $  1,800.00   +100% vs Claude Opus 5
  Claude Sonnet 5   $    360.00   -60% vs Claude Opus 5

agent task (x1)
  Claude Opus 5.5   $      5.36   -34% vs Claude Opus 5
  Claude Opus 5     $      8.15   +0% vs Claude Opus 5
  Claude Fable 5.1  $     11.95   +47% vs Claude Opus 5
  Claude Sonnet 5   $      3.26   -60% vs Claude Opus 5

batch extract (x10,000)
  Claude Opus 5.5   $    110.00   -20% vs Claude Opus 5
  Claude Opus 5     $    137.50   +0% vs Claude Opus 5
  Claude Fable 5.1  $    275.00   +100% vs Claude Opus 5
  Claude Sonnet 5   $     55.00   -60% vs Claude Opus 5

agent task on Opus 5.5 if it emits fewer output tokens than Opus 5
  output - 0%   $5.36   -34% vs Claude Opus 5
  output -25%   $4.56   -44% vs Claude Opus 5
  output -40%   $4.08   -50% vs Claude Opus 5
  output -50%   $3.76   -54% vs Claude Opus 5

Three things stand out. First, on uncached single calls and batch jobs, the saving at equal token counts is exactly the 20% price cut and nothing more. Second, the cache-heavy agent task saves 34% before any token-efficiency gain, purely because cache reads fell from $0.50 to $0.20. Third, and less expected, Fable 5.1 costs only 47% more than Opus 5 on the agent task instead of 100%, because its $0.25 cache read rate is half of Opus 5’s. On cache-heavy loops, the price gap between tiers is much narrower than the headline rates suggest.

The last block is a sensitivity table, not a result. Anthropic says the model “tends to finish the same task with fewer tokens” but publishes no per-task token ratio you could plug in. If Opus 5.5 at medium emits 40% fewer output tokens than Opus 5 at high on your traffic, the agent task lands 50% cheaper. If it emits the same, it lands at 34%. Only your own usage logs can say which. For the general method behind this arithmetic, including the tokenizer multiplier that affects older Claude models, see our breakdown of LLM cost per task.

What this script does not model: fast mode, the 1.1x US-only inference multiplier, the 1-hour cache write rate, web search fees, and retries. Also, all three workloads assume the same token counts across models, which is the one assumption most likely to be wrong.

A Realistic Migration Scenario

Consider a small team running an internal code-review agent on Opus 5 across a few mid-sized repositories. The agent has three routes. A triage route classifies each pull request with thinking disabled to keep it fast. An extraction route forces a report_findings tool to get structured output. A review route runs a multi-turn loop that injects a fresh “focus on security” reminder each turn and removes the previous one.

A model-ID swap on a Friday afternoon would produce three separate failures. The triage route 400s immediately on thinking.type.disabled. Extraction 400s on forced tool_choice. The review loop works in local testing, where the developer’s older account is exempt, and then fails in production if the service runs on an account created after 31 August, because deleting the old reminder edits the prefix.

The sensible sequence takes a few days rather than a few minutes. First, make the review loop append-only while still on Opus 5, since that change is compatible with both models and improves cache hits anyway. Next, move extraction to structured outputs, also on Opus 5. Only then change the model ID, set triage to low effort and review to an explicit level, and compare a week of usage data against the Opus 5 baseline. The trade-off is time: the team spends that week on migration work that ships no features, in exchange for a switch they can attribute and roll back cleanly.

When to Use Claude Opus 5.5

  • You run Opus 5 or Opus 4.8 today and want the same capability tier at lower cost
  • Your workload is agentic and cache-heavy, where the 60% cheaper cache reads compound
  • You were weighing Fable 5.1 and your evals have not yet shown a gap Opus 5.5 can’t close
  • Your harness is already append-only, so the preserved-thinking check costs you nothing
  • You feed it charts, diagrams or screenshots, which Anthropic says it reads more accurately than Opus 5 even at low effort

When NOT to Use Claude Opus 5.5

  • A route depends on thinking being fully off for time to first token, and low effort measures too slow
  • Your code edits conversation history and you cannot make it append-only yet on a post-August account
  • Your computer-use integration runs on a platform that does not yet offer the toolset
  • Sonnet 5 already passes your evals, since it costs half as much per token as Opus 5.5
  • You need fast mode on Bedrock, Google Cloud or Foundry, since it is Claude API only

Common Mistakes with Claude Opus 5.5

  • Swapping the model ID without setting effort, then attributing a quality change to the model
  • Reading response.content[0].text, which now returns an empty thinking block
  • Keeping a max_tokens sized for a thinking-off route, so replies truncate
  • Testing on an old account and deploying to a new one, where prefix edits are enforced
  • Falling back to Opus 5 on refusal and assuming the fallback turn still has the earlier reasoning
  • Rendering only text blocks in an agent UI, which goes silent between tool calls
  • Leaving prompt instructions that asked the model to “show its reasoning” in the answer

Conclusion

Claude Opus 5.5 is a straightforward upgrade on price, 20% cheaper per token and 60% cheaper on cache reads, but it is not a drop-in replacement for Opus 5. Four request shapes now fail, the default effort dropped to medium, and between-tool text moved into thinking blocks. The recommendation: fix the append-only and structured-output changes while still on Opus 5, then switch the model ID with effort set explicitly on every route, and let a week of usage data tell you whether you landed nearer 20%, 34% or 50%. Run the grep above against your codebase today to see how much of that work applies to you. If you are new to the API itself, start with our guide to getting started with the Claude API.