Anthropic API 2026-10-21: temperature Now Returns 400, Even at 1.0

Contents
  1. Which requests return 400 under API version 2026-10-21?
  2. How do you fix each 400?
  3. What changed in the Anthropic SDKs?
  4. Which key does a request use when both headers are sent?
  5. What do you lose by dropping temperature?
  6. How does Synthorai handle API version 2026-10-21?
  7. What should you check before upgrading?
  8. FAQ
  9. Related reading

A Claude request sent with API version 2026-10-21 returns HTTP 400 if it sets temperature, top_p or top_k, even when the value is the default: temperature: 1.0 fails with “temperature: Extra inputs are not permitted”. These are the sampling parameters, which control how randomly the model picks each next token. The API version is the anthropic-version request header, which selects how the Messages API validates and answers a request; the old value is 2023-06-01. The SDK majors Anthropic released with it on October 21 (Python 2.0.0, TypeScript 1.0.0 and five more) send it by default. Those SDKs no longer have the sampling parameters at all, so the 400 reaches code that builds the request body itself: raw HTTP clients and extra body fields. We tested eight request shapes under both versions on Claude Sonnet 4.6 and Claude Sonnet 5.5, compared two Python SDK versions, and repeated the tests through Synthorai.

TL;DR

  • Under 2026-10-21, temperature, top_p and top_k return 400 on Claude Sonnet 4.6 and Sonnet 5.5, including temperature: 1.0.
  • 2026-10-21 also rejects document blocks in assistant messages and citations on user text blocks.
  • Anthropic’s Python SDK 2.x sends the key as Authorization: Bearer; when a request carries both headers, the API uses x-api-key.
  • Through Synthorai, all 32 requests returned 200 with either SDK, including the 12 the Anthropic API rejects under 2026-10-21.

Which requests return 400 under API version 2026-10-21?

Five changes cause the 400s: the three sampling parameters, a document block placed directly in an assistant message, and citations (references from a text block back to a passage in a document) on a text block in a user message. The table tests them as six failing cases plus two that still pass. We sent each case once per model and version to the Anthropic API directly. 200 means the request was accepted; 400 means it was rejected with invalid_request_error.

RequestSonnet 4.6, 2023-06-01Sonnet 4.6, 2026-10-21Sonnet 5.5, 2023-06-01Sonnet 5.5, 2026-10-21
No sampling parameters200200200200
temperature: 1.0 (the default)200400200400
temperature: 0.2200400400400
top_p: 0.9200400400400
top_k: 40200400400400
document block in an assistant message200400200400
citations on a user text block200400200400
citations on an assistant text block200200200200

The error messages under the new version:

RequestError message under 2026-10-21
temperature, top_p, top_k”temperature: Extra inputs are not permitted” (the parameter name changes)
document in an assistant message”messages: `document` blocks can’t be placed directly in `assistant` messages; send them in a `user` message. Found at: messages.1.content.0”
citations on user text”messages: text blocks in `user` messages can’t have `citations`; remove `citations` from them. Found at: messages.0.content.1”

Claude Sonnet 5.5 already rejected non-default sampling values under 2023-06-01, with a different message (“`temperature` is deprecated for this model.”), and accepted temperature: 1.0. Under 2026-10-21 the parameter itself is gone, so the default value fails too. Claude Sonnet 4.6 accepted every case under the old version. Anthropic’s migration guide says the same rules apply to token counting and to each request in a Message Batch (the Batch API, which runs many requests asynchronously at a discount), and it gives no end date for 2023-06-01.

How do you fix each 400?

Remove the three sampling parameters, move documents into user messages, and strip citations from text you send as the user. A request without sampling parameters samples at the defaults, temperature 1.0 included, which is what a 2023-06-01 request without them already did. Citations on Claude’s own earlier replies, and "citations": {"enabled": true} on documents, are still accepted.

With the Python SDK, the request that works under both versions looks like this:

import anthropic

client = anthropic.Anthropic()  # 2.x sends anthropic-version: 2026-10-21

message = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    # no temperature, top_p or top_k: the parameters no longer exist in 2.x
    messages=[{"role": "user", "content": "Summarize this memo in one sentence."}],
)
print(message.content[0].text)

If one request needs a non-default temperature on a model that still accepts it, such as Claude Sonnet 4.6, it has to stay on the old version. Over raw HTTP, that means setting the header yourself:

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model": "claude-sonnet-4-6", "max_tokens": 256, "temperature": 0.2,
       "messages": [{"role": "user", "content": "Pick a number from 1 to 100."}]}'

What changed in the Anthropic SDKs?

The SDK majors that send 2026-10-21 are Python 2.0.0, TypeScript 1.0.0, Go 2.0.0, Java 3.0.0, C# 13.0.0, PHP 1.0.0 and Ruby 2.0.0. Besides the API version, they change how the key is sent and how many credentials a client can hold, and they are licensed under Apache 2.0 instead of MIT. We installed Python SDK 1.17.0 (the last 1.x) and 2.3.0 and pointed each at a local echo server, which records the headers and body of every request it receives:

BehaviorPython SDK 1.17.0Python SDK 2.3.0
anthropic-version sent2023-06-012026-10-21
Header carrying the API keyx-api-keyAuthorization: Bearer
temperature=0.2 as an argumentTypeError, request not sentTypeError, request not sent
temperature through extra_body (raw body fields)sent; the API decidessent; returns 400 under 2026-10-21
Another key in extra_headers={"X-Api-Key": ...}replaces the client’s keyboth keys go out
api_key and auth_token (a bearer token used instead of an API key) togetherboth sentValueError when the client is built
Real request to the Anthropic API200200

The temperature argument was removed from the Python SDK’s message methods in 1.0.0, so Python users meet the server-side 400 only through extra_body (the SDK option that adds raw fields to the request body) or through HTTP clients and libraries that build the request body themselves. The Bearer header works on both API versions: a request with only Authorization: Bearer <key> returned 200 under 2023-06-01 too, so the auth change and the version change can be rolled out separately.

Which key does a request use when both headers are sent?

The Anthropic API uses x-api-key when a request carries both headers. We sent five header combinations under both versions:

Headers on the requestStatus, both versions
x-api-key only200
Authorization: Bearer only200
Both, same key200
Valid x-api-key, invalid Bearer key200
Invalid x-api-key, valid Bearer key401 “invalid x-api-key”

A proxy or gateway in front of Claude can disagree with the API about which key a request used. With SDK 2.x, code that adds a second key through extra_headers={"X-Api-Key": other_key} now sends two keys: the client’s key in Authorization and the other key in x-api-key. The Anthropic API authenticates the request with other_key, while a proxy that reads only Authorization treats it as the client’s key, so per-key quotas, logs and spend limits can land on the wrong key. The guide’s fix on the client side is to send the second key as Authorization: Bearer <other_key>. On the proxy side, read both headers and either apply the API’s order (x-api-key first) or reject requests whose two headers carry different keys.

What do you lose by dropping temperature?

Dropping temperature costs less than a team that relied on temperature: 0 might expect. The migration guide says Claude 4.7 and later models already accept only the default values, so nothing changes for them. On a model that still takes other values, such as Claude Sonnet 4.6, a request that lowered temperature for steadier output loses that effect, and no other setting replaces it. We measured how much that effect was worth: 20 requests per setting to Sonnet 4.6 under 2023-06-01, each with a random request ID appended so no two requests were identical.

Prompttemperature: 0Default (temperature: 1.0)
“Pick a number from 1 to 100”2 distinct answers: 47 (19 times), 42 (1)2 distinct answers: 47 (17), 42 (3)
“Write a coffee shop tagline, at most eight words”1 distinct answer, 20 times1 distinct answer, 20 times

On these short answers, Sonnet 4.6’s output at the default temperature was about as concentrated as at 0, so removing temperature: 0 changed little. temperature: 0 was not a determinism guarantee either: it returned two different numbers in 20 tries. The prompt text moved the output more than the setting did: without the request ID appended, 42 was the most common answer (17 of 20 at temperature: 0); with it, 47 was. If you need repeatable output, compare answers in code or cache them; the sampling parameter did not provide that before.

How does Synthorai handle API version 2026-10-21?

Synthorai accepts requests in either API version and from either SDK, so upgrading to SDK 2.x or sending anthropic-version: 2026-10-21 does not break a request that worked before. We repeated the 16-case matrix for both models through Synthorai with both anthropic-version values: all 32 requests returned 200, including the 12 that the Anthropic API rejects under 2026-10-21. Python SDK 1.17.0 (sending x-api-key) and 2.3.0 (sending Authorization: Bearer) both worked with base_url="https://synthorai.io" and the same key, and so did temperature sent through extra_body.

Synthorai handles it this way for four reasons:

  • One model, several hosts. A Claude model can be served by the Anthropic API, Amazon Bedrock or Google Cloud Vertex AI, and each host takes its own version string. Synthorai sends each host the version that host expects, so the client’s anthropic-version header does not decide how a request is validated.
  • Mixed clients during a migration. Teams upgrade one service at a time, so for weeks the same account sends 2023-06-01 from SDK 1.x and 2026-10-21 from SDK 2.x. Accepting both lets each service move on its own schedule, and the same key works with either SDK’s auth header.
  • Model changes under the same code. Code that sets temperature: 0.2 for Claude Sonnet 4.6 keeps running when the model name changes to Claude Sonnet 5.5, which does not take that parameter, instead of failing on the switch.
  • No failed request for a default. temperature: 1.0 is the value the model uses anyway, so rejecting it would fail the request without changing the output.

The trade-off is that a 200 does not mean every parameter took effect. Sonnet 5.5 takes only the default sampling values, so temperature: 0.2 sent to it through Synthorai succeeds but cannot lower its randomness. If your output depends on a sampling value, compare outputs with and without it on your own prompts; the measurement above found the effect small on short answers.

What should you check before upgrading?

If youCheckChange
Call the API over raw HTTPEvery place that sets anthropic-versionRemove temperature, top_p, top_k before switching to 2026-10-21
Use the Python SDKextra_body and wrappers that add sampling parametersDelete them; nothing replaces them
Need a low temperature on Claude Sonnet 4.6Whether the output actually depends on itKeep that request on 2023-06-01, or drop it after measuring
Send documents or citations back in historyAssistant turns with document blocks, user turns with citationsMove documents into user messages; strip user-side citations
Run a proxy or gatewayWhich header it reads the key fromRead Authorization as well as x-api-key, with the API’s precedence
Call Claude through SynthoraiWhether your output depends on a sampling valueNo request change needed to upgrade; compare outputs with and without the sampling value

FAQ

Why does my Claude request fail with “temperature: Extra inputs are not permitted”? The request was sent with anthropic-version: 2026-10-21, which no longer has the temperature parameter, so any value returns 400, including 1.0. New SDK majors send that version by default. Remove the parameter, or pin 2023-06-01 for requests that need a non-default value on a model that still accepts one.

Is anthropic-version 2023-06-01 being retired? Anthropic has not announced an end date for 2023-06-01: the migration guide and the API release notes from October 21 give none. Requests that set the header explicitly keep the old behavior, which is how a single request can keep using temperature on Claude Sonnet 4.6.

Does the Anthropic API still accept the x-api-key header? The Anthropic API accepts both x-api-key and Authorization: Bearer on both versions; only the SDKs changed which one they send. When both headers are present, the API uses x-api-key.

← Back to blog