I was about to update the dependencies of a small Python script from a side project. Before running pip install -U anthropic, I opened the official release notes, just to be safe.
That is where I saw it: API version 2026-10-21, and a new set of SDKs that send it by default. Python is now 2.0.0.
Before touching a real key, I swapped the transport for a mock and checked what changes, one item at a time. This post is the record of that.
The short version
The first thing I want to tell you is that the breakage narrows to three places.
| Symptom | Cause | Where to look first |
|---|---|---|
| A call that passes `temperature` raises TypeError | The sampling arguments were removed from the SDK | Your `messages.create` call sites |
| Auth fails behind a proxy or gateway | The key now travels as `Authorization: Bearer`, not `X-Api-Key` | Header handling on the gateway |
| ValueError at startup, or a warning | A client can now hold only one credential | The constructor and your environment variables |
Prepare the code fixes first, then bump the SDK. The official migration guide also tells you to release the upgrade together with the fixes.
1. Calls that pass temperature stop before they are sent
According to the migration guide, with 2026-10-21 the server returns a 400 if you send temperature, top_p, or top_k — even at the default value.
The SDK stops earlier than that. On a client wired to a mock transport, nothing went out on the wire:
# Passing temperature with SDK 2.0.0 (on a mock transport)
c.messages.create(model="claude-sonnet-4-6", max_tokens=10,
temperature=0.2, messages=[{"role": "user", "content": "hi"}])
# TypeError: Messages.create() got an unexpected keyword argument 'temperature'Because the error comes from the SDK, no API 400 appears in your logs. It looks like a failure without any request, which confused me for a moment.
The fix is just deleting the argument, but one judgment call remains. Claude 4.7 and later models only accept defaults anyway, so nothing changes for them. On models that accept other values, such as Sonnet 4.6, a call that lowered the temperature for steadier output loses that effect.
The guide lists no replacement setting. If a call must stay pinned, you keep that one call on the older API version.
2. The key header changed, so check the gateway
The second change works quietly. The new SDK sends your API key as Authorization: Bearer <key> instead of X-Api-Key.
I looked at the headers that reached the mock:
authorization: Bearer sk-ant-test
anthropic-version: 2026-10-21The Claude API accepts either header, so a direct connection is unaffected.
Trouble starts when you have a proxy or gateway in between. If it reads X-Api-Key to swap keys or to mask them in logs, it now has to read a different header.
If you cannot change the gateway, the guide shows how to move the key back to the old header from the SDK side. I ran the same function against the mock, and only x-api-key arrived:
import httpx2
from anthropic import Anthropic, DefaultHttpxClient
def send_x_api_key(request: httpx2.Request) -> httpx2.Request:
# Move the key from Authorization to X-Api-Key
if request.headers.get("Authorization") == f"Bearer {api_key}":
del request.headers["Authorization"]
request.headers["X-Api-Key"] = api_key
return request
client = Anthropic(api_key=api_key,
http_client=DefaultHttpxClient(auth=send_x_api_key))The function runs on every retry too, so once written, nothing slips through.
3. Two credentials either stop the client or raise a warning
The third one appears in environments that hold both a key and a token. In the new SDK, a client holds exactly one credential.
Pass two to the constructor and it stops on the spot:
Anthropic(api_key="a", auth_token="b")
# ValueError: Pass at most one of `api_key=`, `auth_token=`, `credentials=`,
# `config=`, or `profile=`. Received `api_key=`, `auth_token=`.With environment variables it does not stop; a precedence order picks one. When I set both ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN, a warning appeared once and the key was used:
Anthropic: ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN are both set. Using ANTHROPIC_API_KEY.This is the one I think is easiest to miss. A hard stop gets noticed; a quiet choice lets the setting you meant as a token go unused while everything keeps running.
If you used to send a token for a gateway and a key for the API behind it, pass the token as auth_token and put the key in default_headers. The gateway must also strip its Authorization header before forwarding.
The order I check in before upgrading
This is where I settled. Short steps only.
- Search the call sites for
temperature,top_p, andtop_k - Decide whether any call must stay pinned to the older API version
- Confirm no gateway or internal proxy reads
X-Api-Key - Check that
ANTHROPIC_API_KEYandANTHROPIC_AUTH_TOKENare not both set - Run once on the mock, then call the real API a single time
Also note that calling MessageParam(...) like a function now fails with TypeError: Cannot instantiate typing.Union, since it became a union type in 2.0.0; writing messages as dicts is unaffected. And if you call older models on Bedrock, the new API version is not available there, so you stay on your current SDK.
The line I want to keep
Before a dependency update touches a real key, run it once on a mocked transport. Your own output shows where things break before the release notes do.
All three places are written in the official migration guide. Even so, I could not tell which ones my environment would hit until I ran it.
Please start with a search for temperature in your own scripts.
I now keep a fixed day for dependency updates and run the mock check alongside it.