If you upgraded the Anthropic SDK recently and your Claude calls started failing, the error probably looks like this:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "`temperature` is deprecated for this model."
},
"request_id": "req_..."
}
The short fix: stop sending temperature, top_p and top_k to Claude. The rest of this post explains why it happened, why Python users often see a different error, which frameworks still send these values for you, and what to do if your app depended on a low temperature.
What changed on 21 October
Anthropic released a new API version, 2026-10-21. Under it, a request that includes temperature, top_p or top_k returns a 400 error, "even at the parameter's default value." That last part is what catches people. Sending temperature: 1, which used to be harmless, now fails too.
This didn't come out of nowhere. Since Claude Opus 4.7 in April, the newer models have refused any non-default sampling value. The new API version stops accepting the parameters altogether.
You get the new version in one of two ways:
- You upgraded the SDK. The first releases that use
2026-10-21areanthropic2.0.0 for Python and@anthropic-ai/sdk1.0.0 for TypeScript, along with new major versions of the C#, Go, Java, PHP and Ruby SDKs and the CLI. Anthropic's SDKs send whichever API version was current when their major version came out, so a major upgrade moves you onto the new rules without any other change in your code. - You call the HTTP API yourself and set the
anthropic-versionheader to2026-10-21.
If you're still on an older SDK major version, or you send anthropic-version: 2023-06-01, the new rule doesn't apply to you yet.
Two different errors, depending on your SDK
Python users often never see the 400. Recent versions of the anthropic package removed temperature, top_p and top_k from messages.create() entirely, so passing one fails inside the SDK before any request is sent:
TypeError: Messages.create() got an unexpected keyword argument 'temperature'
The SDK's migration notes suggest passing the values through extra_body for older models that still use them. That workaround is exactly what turns into the 400 once you're on version 2.0 and API version 2026-10-21. So if you see the TypeError, delete the argument rather than moving it into extra_body.

Which requests fail

| API version 2023-06-01 | API version 2026-10-21 | |
|---|---|---|
| Claude 4.7 and later (for example Opus 5.5, Sonnet 5.5, Fable 5.1), and Claude Mythos Preview | 400 if you send a non-default value | 400 if you send the parameter at all |
| Earlier models (for example Sonnet 4.6, Haiku 4.5) | Any value works | 400 if you send the parameter at all |
On Amazon Bedrock, version 2026-10-21 is only available for Claude 4.7 and later. More on Bedrock below.
The fix
Remove the three parameters. With the Python SDK:
import anthropic
client = anthropic.Anthropic()
message = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=1024,
# temperature=0.2, # remove it: a TypeError on recent SDKs, a 400 on API version 2026-10-21
messages=[{"role": "user", "content": "Classify this support ticket: ..."}],
)
print("".join(b.text for b in message.content if b.type == "text"))
If one shared function builds requests for several providers, strip the parameters for Claude only, so your GPT and Gemini calls keep their settings:
SAMPLING_KEYS = ("temperature", "top_p", "top_k")
def request_params(model: str, params: dict) -> dict:
if model.startswith("claude"):
return {k: v for k, v in params.items() if k not in SAMPLING_KEYS}
return params
Calling Claude through an OpenAI-compatible endpoint doesn't get you around this. Anthropic's own OpenAI SDK compatibility layer already returns a 400 on Claude 4.7 and later for any temperature below 1, any top_p other than the default, or both set together. Many gateways pass these values straight through to the model, so the reliable fix is the same on every route: don't send them to Claude.
When a framework sends it for you
Often the parameter isn't in your code at all. It's in a framework default or a config file. Where the main ones stood on 31 October:
- LangChain.
langchain-anthropic1.7.7 dropped its cap on the Anthropic SDK version, so upgrading it can pull in SDK 2.x.ChatAnthropiconly sendstemperatureif you set it, but when you do, it passes it throughextra_body, which gets you the 400 on SDK 2.x. Removetemperaturefrom yourChatAnthropic(...)setup. - Vercel AI SDK.
@ai-sdk/anthropicstill sendsanthropic-version: 2023-06-01and drops sampling settings for models that reject them, with an "unsupported" warning. The Bedrock provider got the same fix after a bug report in September. - LlamaIndex.
llama-index-llms-anthropic0.12.3 has an open bug: it breaks on SDK 1.x because of thetemperatureargument, and on 2.x for a different reason. The reporter's workaround is pinninganthropic<1until a fix ships. - Pydantic AI. It drops the parameters and logs a warning on every request.
If you use another framework, search its config for temperature, top_p and top_k, and check whether it pins the Anthropic SDK version.
Staying on the old API version for now
If you can't change the request code yet, you can stay on the old behavior two ways:
- Pin the SDK below the new major version:
anthropic<2for Python,@anthropic-ai/sdk<1for TypeScript. Anthropic's own docs suggest pinning the version you use today in some migration cases. This is the safer option. - Override the header:
anthropic.Anthropic(default_headers={"anthropic-version": "2023-06-01"}). Anthropic documents this, but warns that overriding default headers "might result in incorrect types and other unexpected or undefined behavior in the SDK."
Either way, it only helps on older models. Claude 4.7 and later reject non-default values on both API versions. And the older models are on a clock: claude-sonnet-4-5-20250929 retires on 30 November 2026, with claude-sonnet-5-5 as its replacement, and Sonnet 4.6 is listed as retiring no sooner than 17 February 2027.
Claude on Bedrock and Vertex AI
On Amazon Bedrock, SDK 2.x's AnthropicBedrock client sends 2026-10-21, which Bedrock only accepts for Claude 4.7 and later. An open SDK issue reports older models such as Sonnet 4.5, Opus 4.5 and Opus 4.6 answering with a different 400: Invalid API version: 2026-10-21. If you call those models on Bedrock, keep the Bedrock client on SDK 1.x until you move to a newer model.
On Google's Vertex AI, the version goes in the request body, and Anthropic says both vertex-2023-10-16 and 2026-10-21 are accepted.
What if you need temperature 0?
This is the real question. Plenty of teams set a low temperature for classification, extraction or anything that should give the same answer twice. No other setting replaces it. Anthropic's advice is to "use prompting to guide model behavior", and on models that support it, structured outputs are the closest thing to a consistency switch. You give Claude a JSON schema, and the response has to match it:
from typing import Literal
import anthropic
from pydantic import BaseModel
class Ticket(BaseModel):
category: Literal["billing", "bug", "feature_request"]
client = anthropic.Anthropic()
response = client.messages.parse(
model="claude-sonnet-5-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Classify this support ticket: ..."}],
output_format=Ticket,
)
print(response.parsed_output.category)
messages.parse() turns the Pydantic model into a schema, sends it as output_config.format, and validates the reply. Two caveats from Anthropic's docs: the capitalization of enum values isn't guaranteed, and a reply that stops because of a refusal or the max_tokens limit may not match the schema. So keep a check after it.
Beyond that:
- Put two or three worked examples in the prompt.
- Check the output and retry on a mismatch, instead of hoping the model never produces one.
- Don't reach for the old tricks. Prefilling the start of Claude's answer isn't supported on Claude 4.6 and later, and forcing a specific tool with
tool_choicefails on some current models and settings (autostill works).
Put bluntly: if a pipeline only worked because temperature was 0, it was more fragile than it looked. Validation catches drift. A low temperature only made it rarer.
Catching it in code
The SDK retries rate limits and server errors, but a 400 fails straight away. Catch the typed error rather than matching message text:
try:
message = client.messages.create(**params)
except anthropic.BadRequestError as e:
# e.status_code is 400; log e.request_id for Anthropic support
if any(k in e.message for k in SAMPLING_KEYS):
params = request_params(params["model"], params) # strip sampling keys, retry once
message = client.messages.create(**params)
else:
raise
Other changes in the same release that can break things
The temperature change gets the attention, but 2026-10-21 has a few more:
- The SDKs and the CLI now send your key as
Authorization: Bearer <key>instead ofX-Api-Key. The Claude API accepts either, but a proxy or gateway in the middle that only readsX-Api-Keywill start rejecting your requests. - Passing two credentials to one client is now an error (a
ValueErrorin Python, aTypeErrorin TypeScript). - Document blocks in
assistantmessages return a 400, and so docitationsontextblocks inusermessages. - Client-side compaction (
compactionControlin TypeScript) is gone. Anthropic points tocontext_managementinstead. - The legacy Text Completions API is removed from the TypeScript, Go, Java and Ruby SDKs and the CLI.
- The SDKs and CLI are now licensed under Apache 2.0 instead of MIT. No code changes are needed, but your legal team may want to know.
Read the full migration guide before you upgrade the SDK in production. It's long, but most of it is type renames you'll only notice at compile time.
Using Claude through Aight
Aight sells Claude Opus 5.5, Sonnet 5.5, Fable 5.1, Haiku 4.5 and a few older Claude models through one OpenAI-compatible API, at Anthropic's list prices. Sonnet 5.5 is $2 / $10 per million tokens, input / output, and Opus 5.5 is $4 / $20. The rule above applies there too: leave temperature and top_p out of Claude requests.
Where one key does help is the question that usually comes next: does another model handle this task better without a temperature knob? You can run the same prompts through Claude, GPT and Gemini on the same key and compare, with no new accounts:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.getaight.ai/v1",
api_key=os.environ["AIGHT_API_KEY"],
)
prompt = [{"role": "user", "content": "Classify this support ticket as billing, bug or feature request: ..."}]
for model in ["claude-sonnet-5-5", "gpt-5.6-terra", "gemini-3.1-pro-preview"]:
reply = client.chat.completions.create(model=model, messages=prompt)
print(model, "->", reply.choices[0].message.content)
Balance is prepaid in US dollars and doesn't expire. Recharges start at $5 plus a 3% processing fee, and each one adds 10% extra balance. The quickstart covers sign-up to first request.
If you've removed all three parameters and still get a 400, read the message again. The same release added a few other 400s, and the message names the field that caused it.
Sources
- Anthropic, API version 2026-10-21 migration guide
- Anthropic, Model deprecations: sampling parameter rules, Sonnet 4.5 and 4.6 dates
- Anthropic, Structured outputs, Increase output consistency, Define tools
- Anthropic, Python SDK (default headers) and the SDK's MIGRATION.md
- Anthropic, OpenAI SDK compatibility
- Frameworks: LangChain PR #41407, Vercel AI #21380, LlamaIndex #23701, Pydantic AI #12031
- Bedrock: anthropic-sdk-python #2031
- Example reports of the error: Umbraco.AI #268, BoltAI #410
- Aight, Models and pricing
Checked on 31 October 2026.