Anthropic API Version 2026-10-21: Every Breaking Change and How to Upgrade the SDKs

Quick answer. On October 21, 2026 Anthropic released API version 2026-10-21, the first new anthropic-version since 2023-06-01, together with new SDK majors (Python 2.0.0, TypeScript 1.0.0, Go 2.0.0, Java 3.0.0, C# 13.0.0, PHP 1.0.0, Ruby 2.0.0, ant CLI 2.0.0) that send it by default. If your Claude calls started returning 400 after a dependency bump, the usual causes are temperature, top_p or top_k in the request (rejected even at default values), document blocks inside assistant messages, or non-empty citations on text blocks in user messages. Remove those, update proxies that read X-Api-Key (the SDKs now send Authorization: Bearer), and keep only workloads that truly depend on a non-default temperature on anthropic-version: 2023-06-01.

For three years, every request to the Claude API carried the same header: anthropic-version: 2023-06-01. That changed on October 21, 2026. Anthropic shipped API version 2026-10-21 and, on the same day, a new major release of every official SDK and the ant CLI. Those releases send anthropic-version: 2026-10-21 on every request by default, so a routine pip install -U or Dependabot merge can turn working code into a stream of 400 errors without a single line of your code changing.

Some of the breakage comes from the API version itself (rejected parameters and message shapes). Some comes from the SDKs, which changed independently of the API version: a role-discriminated MessageParam type, a new auth header, a one-credential rule, removed Text Completions, and a license change from MIT to Apache 2.0.

This guide is organized by symptom. Start with the table, jump to the section that matches your error, then use the per-SDK notes and rollout checklist to finish the upgrade. Everything below is taken from Anthropic's official migration guide, the API versions page, and the platform release notes, as of October 2026.

Symptom-to-fix table

SymptomCauseFix
400 on every Messages call that sets temperature, top_p or top_k, even temperature=1.0Sampling parameters are removed in 2026-10-21Delete the parameters. If a workload depends on a non-default value, keep it on 2023-06-01 (previous SDK major in its own service, or raw HTTP)
400 when replaying a conversation that contains a PDF or text documentA document block sits directly in an assistant messageMove the document into a user message
400 when sending back retrieved snippets or search resultsA text block in a user message carries a non-empty citations array (including inside search_result blocks)Strip citations from user-side text blocks
client.completions is undefined / method not found (TypeScript, Go, Java, Ruby, CLI)Text Completions removed from those SDKs and the CLIPort to the Messages API
401 or 403 from your own gateway, proxy, or test stubSDKs now send the key as Authorization: Bearer <key> instead of X-Api-KeyHave the proxy read Authorization, or set X-Api-Key yourself
TypeError when calling MessageParam(...) in PythonMessageParam is now a union of role-specific typesWrite messages as dicts
ValueError / TypeError constructing the clientBoth an API key and an auth token were passed; a client now holds one credentialPass exactly one credential
Admin or Analytics dashboards show blanks or KeyErrorRenamed response fields (roles, group_id, name, and others)Read the new field names
flag provided but not defined from ant--api-key and --auth-token flags removed in CLI 2.0.0Use ANTHROPIC_API_KEY, --api-key-stdin, or ant auth login

What actually changed on October 21, 2026

Three of the four October 21 release-note items matter to most teams: the new API version, new SDK and CLI majors that send it by default, and SDK breaking changes that don't depend on the API version, including a license change from MIT to Apache 2.0. (The fourth adds enforcement_status and enforcement_actions fields to user profiles.) The SDK versions that are the first to send 2026-10-21:

PackageFirst version on 2026-10-21Notes
Python anthropic2.0.0MessageParam becomes a union; one credential per client
TypeScript @anthropic-ai/sdk1.0.0Upgrade Bedrock, Vertex, Foundry, AWS and Google Cloud packages to v1 at the same time
Go anthropic-sdk-go2.0.0New module path github.com/anthropics/anthropic-sdk-go/v2; Go 1.25 or later required
Java com.anthropic:anthropic-java3.0.0MessageParam.builder() replaced by ofUser / ofAssistant / ofSystem
C# Anthropic13.0.0IChatClient adapters ignore sampling options
PHP anthropic-ai/sdk1.0.0Use composer require; composer update stays inside your constraint
Ruby anthropic2.0.0Text Completions removed; compaction_control: removed
ant CLI2.0.0Go install path gains /v2

Starting with these versions, the SDKs and CLI are licensed under the Apache License 2.0 instead of MIT. Earlier versions remain MIT. No code change is needed, but if legal or security tracks dependency licenses, update those entries.

One platform caveat: the new SDKs' Amazon Bedrock and Google Cloud clients also send 2026-10-21, so every breaking change below applies there too. On Bedrock, 2026-10-21 is available only for Claude 4.7 and later models. If you call an older model on Bedrock, Anthropic's guidance is to stay on your current SDK version (or keep sending your current version header) until you have moved that traffic to a 4.7-or-later model.

Fix 1: temperature, top_p and top_k return 400

This is the change most teams will hit first. Under 2026-10-21, a Messages, token-counting (POST /v1/messages/count_tokens) or Message Batches request that includes temperature, top_p, or top_k returns a 400 error on every model, even when the value equals the default. The new SDK majors also remove the three parameters from their types, so in typed code the failure often shows up at compile or lint time instead of at runtime.

Leaving the parameters out gives you the defaults, including temperature 1.0, which is the same sampling a 2023-06-01 request gets when it omits them. For Claude 4.7 and later models (including Claude Opus 5.5, Claude Sonnet 5.5 and Claude Haiku 5.5), which already accept only default sampling values, nothing about output behavior changes. On older models that accepted other values, such as Claude Sonnet 4.6, a request that lowered temperature for more consistent output loses that effect, and Anthropic states plainly that no other setting replaces it.

Python: before and after

# Before: anthropic 1.x, sends anthropic-version 2023-06-01
import anthropic

client = anthropic.Anthropic()

message = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    temperature=1.0,  # accepted on 2023-06-01, rejected with 400 on 2026-10-21
    messages=[{"role": "user", "content": "Summarize this incident report."}],
)

# After: anthropic 2.0.0, sends anthropic-version 2026-10-21
import anthropic

client = anthropic.Anthropic()

message = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Summarize this incident report."}],
)
print(message.content[0].text)

TypeScript: before and after

// Before: @anthropic-ai/sdk 0.x
const message = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 1024,
  temperature: 1.0, // 400 under 2026-10-21; also gone from the v1 types
  messages: [{ role: "user", content: "Summarize this incident report." }],
});

// After: @anthropic-ai/sdk 1.0.0
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const message = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Summarize this incident report." }],
});

Watch for indirect callers. Framework adapters, eval harnesses, and shared config objects often inject temperature: 0 for "deterministic" runs. The C# SDK's IChatClient adapters now silently ignore ChatOptions.Temperature, TopK and TopP; other wrappers may not be as forgiving.

Fix 2: document blocks in assistant messages

Under 2026-10-21, a request that places a document block directly in an assistant message returns 400. This usually appears in apps that synthesize conversation history, for example by inserting a fake assistant turn that "contains" a file. Send documents in user messages instead.

Documents nested inside another block are still accepted. A web fetch tool result that Claude returned, which contains a document, can be sent back unchanged.

Fix 3: citations on text blocks in user messages

A text block with a non-empty citations array inside a user message now returns 400, including text blocks inside search_result blocks. RAG pipelines that copy Claude's cited answer into the next user turn, or that pre-populate citations on search results, are the typical culprits.

Citations on text blocks in assistant messages (Claude's earlier replies that you send back) are still accepted, and so is the "citations": {"enabled": true} setting on documents and search results. Only the user-side citation arrays have to go. A small sanitizer before each request is enough:

def strip_user_citations(messages: list[dict]) -> list[dict]:
    """Remove citations arrays from text blocks in user messages."""
    for message in messages:
        if message["role"] != "user" or isinstance(message["content"], str):
            continue
        for block in message["content"]:
            if block.get("type") == "text":
                block.pop("citations", None)
            elif block.get("type") == "search_result":
                for inner in block.get("content", []):
                    if inner.get("type") == "text":
                        inner.pop("citations", None)
    return messages

Fix 4: Text Completions is gone from four SDKs and the CLI

The legacy Text Completions API is removed from the TypeScript, Go, Java and Ruby SDKs and from the ant CLI. Anthropic notes that newer models and features don't support it. If you still have client.completions.create(...) calls with \n\nHuman: / \n\nAssistant: prompts, port them to the Messages API: move the human turns into messages with role: "user", move any preamble into system, and replace max_tokens_to_sample with max_tokens.

If the code that still uses Completions also targets an old model, check whether that model is approaching retirement. Claude Sonnet 4.5, for example, retires on the Claude API on November 30, 2026, so plan the model move and the Messages port together if you need to do both.

Fix 5: API keys are sent as Authorization: Bearer

The new SDKs and the CLI send your API key as Authorization: Bearer <key> instead of X-Api-Key: <key>. The Claude API accepts a key in either header, so direct calls keep working. What breaks is anything in between that reads or rewrites X-Api-Key: an internal LLM gateway, a reverse proxy that injects the key, a log scrubber, a middleware that rate-limits by key, or a test stub that asserts on headers.

The preferred fix is to update the proxy to read Authorization. If you can't touch the proxy yet, set the old header yourself. In TypeScript:

import Anthropic from "@anthropic-ai/sdk";

const apiKey = process.env.ANTHROPIC_API_KEY!;

const client = new Anthropic({
  apiKey,
  // Send the key the old way and stop the Bearer header from going out.
  defaultHeaders: { "X-Api-Key": apiKey, Authorization: null },
});

In Python, the migration guide shows passing an auth function to DefaultHttpxClient that moves the key from Authorization back to X-Api-Key on every request, including retries. A few related details are easy to miss:

  • Per-request key overrides changed. In Python, extra_headers={"X-Api-Key": other_key} no longer replaces the client's key: both keys go out. Use extra_headers={"Authorization": f"Bearer {other_key}"}. The TypeScript equivalent is headers: { Authorization: `Bearer ${otherKey}` }.
  • Not every platform client switched. The Foundry clients (AnthropicFoundry in Python, @anthropic-ai/foundry-sdk in TypeScript) still send x-api-key. The AWS clients now use Bearer, and the Bedrock Mantle clients already did.
  • A client holds one credential. Because the key and the auth token now share a header, passing both raises an error: ValueError in Python, TypeError in TypeScript, IllegalStateException in Java, ArgumentException in C#. With nothing passed in code, the client takes the first credential it finds, starting with ANTHROPIC_API_KEY then ANTHROPIC_AUTH_TOKEN, and logs a warning once when both are set.

SDK type changes: MessageParam is a role-discriminated union

Across all SDKs, MessageParam is now a union of UserMessageParam, AssistantMessageParam and SystemMessageParam (and BetaMessageParam splits the same way). Requests carry the same fields and values as before (in Go and Java, only the key order in a beta system message changes); this is mainly a type-level change, but it does produce runtime errors in a few cases.

Python

Dict literals such as {"role": "user", "content": "Hello"} need no change. Calling MessageParam(...) or subclassing it now raises TypeError:

# Before (anthropic 1.x)
message = MessageParam(role="user", content="Hello")

# After (anthropic 2.0.0)
message: MessageParam = {"role": "user", "content": "Hello"}

Type checkers also flag a dict whose role is a variable spanning more than one role, because it matches no single member of the union. Build one dict per role:

from typing import Literal

from anthropic.types import MessageParam


def to_message(role: Literal["user", "assistant"], text: str) -> MessageParam:
    if role == "user":
        return {"role": "user", "content": text}
    return {"role": "assistant", "content": text}

TypeScript

Literals that name their role type-check as before. Two patterns break: code that spreads a message of any role while replacing content, and interfaces that extend MessageParam (an interface can't extend a union):

// Before
interface StoredMessage extends Anthropic.MessageParam {
  id: string;
}
const copy: Anthropic.MessageParam = { ...message, content: blocks };

// After
type StoredMessage = Anthropic.MessageParam & { id: string };
const copy: Anthropic.MessageParam =
  message.role === "system" ? message : { ...message, content: blocks };

Go, Java, C#, PHP, Ruby in brief

  • Go: MessageParam has OfUser, OfAssistant and OfSystem fields; MessageParamRole constants are gone. NewUserMessage, NewAssistantMessage and ToParam keep working. Change every import to the /v2 module path and run go get github.com/anthropics/anthropic-sdk-go/v2.
  • Java: MessageParam.builder() is gone; use MessageParam.ofUser("..."). Builder methods such as addUserMessageOfBlockParams become addUserMessageOfContentBlockParams.
  • C#: build new UserMessageParam { Content = "..." } instead of setting Role = Role.User; the Role enums are gone.
  • PHP: role is now the first positional argument of MessageParam::with(), so positional calls in the old order fail; instanceof MessageParam is always false.
  • Ruby: message.is_a?(Anthropic::MessageParam) returns false; use messages.grep(Anthropic::MessageParam) and message.role.

Other SDK and CLI changes worth scanning

  • Models methods: non-beta client.models.list() / retrieve() no longer accept betas. Call client.beta.models.list(betas=[...]) instead.
  • TypeScript and Ruby tool runner: client-side compactionControl / compaction_control: is removed in favor of server-side compaction via context_management (with betas: ["compact-2026-01-12"] and an edit of type compact_20260112), with a trigger threshold of at least 50,000 tokens.
  • One-value enums become constants in the C#, Go, Java, PHP and Ruby SDKs, mostly on Managed Agents types. Delete the redundant Type field when building objects and compare against the literal value when reading: a string in Go and PHP, a symbol in Ruby (:"agent.message"), and a JsonValue in Java (_type().equals(JsonValue.from("agent.message"))).
  • Java: interceptors now see anthropic-version before they run, so an interceptor that sets its own version must call replaceHeaders; several getters now return Optional.
  • CLI: --api-key and --auth-token are removed because flag values leak into shell history and process listings. If you install with go install, the path is now github.com/anthropics/anthropic-cli/v2/cmd/ant@latest; the old path silently keeps installing v1.
  • Platform-client and credential edge cases: the guide also covers smaller per-SDK changes, such as the removal of DefaultVersion constants on the Vertex and Bedrock clients in Go and Ruby, TypeScript platform clients rejecting credentials they don't authenticate with, and C# platform clients ignoring credentials set through WithOptions. If you use a cloud platform client or override credentials per request, read your language's section of the official guide end to end.

Admin API and Enterprise Analytics API field renames

If you have internal tooling that syncs RBAC groups, audits API keys, or builds usage dashboards, these renames will break it quietly: responses under 2026-10-21 no longer include the old names at all.

APIEndpointsOld fieldNew field
AdminRBAC groups (create, list, retrieve, update)rolesrole_ids
AdminRBAC group members (list, add, remove response)group_idrbac_group_id
AdminRBAC roles (list, retrieve)namedisplay_name
AdminOrganization and workspace rate limitsgroup_typegroup.type
AdminAPI keys (list, retrieve, update)workspace_idscope (different values)
Enterprise AnalyticsPer-user usage and cost reportsactor.emailactor.email_address
Enterprise AnalyticsActivity summariessummariesdata

The API key change needs logic, not just a rename. Under 2023-06-01, workspace_id was null both for Default Workspace keys and for all-workspaces keys. Under 2026-10-21, a workspace-bound key (including the Default Workspace) has scope.workspace_id set to that workspace's real ID, and an all-workspaces key has scope of {"type": "organization"}. If your code treated null as "Default Workspace", look up the Default Workspace ID via List Workspaces with include_default=true and compare against it. The group_type query parameter and the workspace_id filter on list endpoints are unchanged.

Stopgap: keep specific calls on 2023-06-01

Anthropic's guide is explicit that a request relying on a non-default sampling value can stay on 2023-06-01. Because the new SDK majors no longer expose temperature, top_p or top_k, the practical way to do that is to keep those calls on the previous SDK major, which sends 2023-06-01:

# Python: stay on the 1.x line for now
pip install "anthropic>=1,<2"

# TypeScript: stay on the 0.x line for now
npm install "@anthropic-ai/sdk@<1"

A pin applies to the whole service or virtualenv, not to individual calls: you can't run anthropic 1.x and 2.x side by side in one Python environment, and running two majors of @anthropic-ai/sdk in one Node app is awkward at best. Either isolate the temperature-dependent workload in its own service, or send just those requests over raw HTTP with anthropic-version: 2023-06-01 while the rest of the codebase moves to the new SDK.

If you call the API over raw HTTP, keep sending anthropic-version: 2023-06-01 on those requests and 2026-10-21 on the rest. Under Anthropic's versioning policy, existing input and output parameters are preserved for a given version, so pinned calls should keep behaving as they do today.

Treat this as a bridge, not a destination. Anthropic recommends the latest API version whenever possible, the newest models (Claude 4.7 and later) don't honor non-default sampling values anyway, and staying on an old SDK major means skipping the type and auth changes you'll eventually have to make. As of October 2026, the versioning page does not list a retirement date for 2023-06-01. If a workload genuinely needs low-variance output, invest in structured outputs, strict tool use, or tighter prompts rather than parking on the old version indefinitely.

Let Claude Code do the first pass: /claude-api api-version

Claude Code 2.1.307 added a /claude-api api-version command that moves Claude API code to API version 2026-10-21, according to the Claude Code changelog. For a repository with many call sites, running it on a branch is a reasonable way to produce a first-pass diff toward 2026-10-21. The changelog doesn't list exactly what it edits, so expect changes such as removed sampling parameters and SDK type updates, and check what it actually touched. Review that diff as you would any automated refactor. It can't know whether a temperature=0.2 was load-bearing for your eval suite, and it won't see a gateway config that lives in another repo. If Claude Code itself throws errors during the run, our Claude Code troubleshooting guide covers the common ones.

A rollout checklist that avoids surprise 400s

  1. Pin before you plan. If Dependabot or Renovate auto-merges minor and major bumps, pin anthropic / @anthropic-ai/sdk below the new major until the migration branch is ready.
  2. Upgrade packages in lockstep. In TypeScript, move @anthropic-ai/bedrock-sdk, vertex-sdk, foundry-sdk, aws-sdk and google-cloud-sdk to v1 together with the core SDK, or your package manager will install a second, older copy of @anthropic-ai/sdk. In Go, update every import path to /v2.
  3. Fix the API-level breaks: remove sampling parameters, move documents out of assistant turns, strip user-side citations.
  4. Fix the SDK-level breaks: message types, one credential per client, Bearer auth in proxies and middleware, Text Completions call sites.
  5. Update Admin and Analytics consumers to the new field names and the scope logic for API keys.
  6. Test against 2026-10-21 in staging, then release the SDK bump and the code fixes together, as Anthropic's guide recommends.
  7. Update license records from MIT to Apache 2.0 for the new SDK and CLI versions.

Inventory the call sites. Search for the patterns that break:

grep -rnE "temperature|top_p|top_k|completions\.create|MessageParam\(|[Xx]-[Aa]pi-[Kk]ey|citations" src/

Also check shared config files, eval harnesses, and any LLM gateway or proxy repo.

If the same sprint also includes a model change, sequence it deliberately. Model migrations bring their own 400s (for example, forced tool_choice and manual thinking budgets are rejected on several 5.x models), so doing the API version and the model move as separate releases makes failures easier to attribute. Our Claude Opus 5.5 migration guide covers the model-side changes.

FAQ

Will my existing code break if I don't upgrade the SDK?

No. Earlier SDK and CLI versions send anthropic-version: 2023-06-01, and Anthropic's versioning policy preserves existing input and output parameters for a given version. The break happens when you install the new major (or set the header to 2026-10-21 yourself) without making the code changes.

Why does temperature=1.0 fail if 1.0 is the default?

Because the parameters are removed, not restricted. Under 2026-10-21, sending temperature, top_p or top_k at any value returns 400. Omitting them gives you the same default sampling.

Is there a replacement for low temperature?

Anthropic says no other setting replaces it. For newer models it was already moot, since Claude 4.7 and later accept only the defaults. For consistency, rely on structured outputs, strict tool use, and prompt design.

Does the Python SDK 2.0 remove Text Completions?

No. Anthropic's migration guide lists the Text Completions removal only for the TypeScript, Go, Java and Ruby SDKs and the ant CLI, not Python 2.0.0. Newer models and features still don't support Text Completions, so port to the Messages API anyway.

Do I need to change anything for Amazon Bedrock?

Yes, the same code changes apply on Bedrock, because the new SDKs' Bedrock clients send 2026-10-21 too. The extra Bedrock caveat: 2026-10-21 is available there only for Claude 4.7 and later, so keep older-model Bedrock traffic on your current SDK version until you switch models.

Is the license change a problem for commercial use?

The SDKs and CLI moved from MIT to Apache License 2.0, a permissive license widely used in commercial software. No code change is needed; update your dependency license inventory and check it against your organization's policy.

Sources

If an SDK or model migration is competing with your roadmap, Codersera can help you hire vetted remote developers, Python and TypeScript included, to own the upgrade, from call-site inventory to staged rollout. Hire vetted remote Python developers.