Claude API version 2026-10-21: temperature is gone, and how to test the upgrade
On 21 October 2026 Anthropic published the first new version of the Claude API since 2023-06-01. Every request carries an anthropic-version header, and the new value is 2026-10-21. The new major SDK releases send it by default, so a routine dependency bump is enough to move you onto it.
Most of the changes are small, but one of them breaks a line that appears in a lot of code: temperature is gone. This post lists what changed, according to Anthropic's version history, and gives you a grep, a curl and a small contract test to check your code before you upgrade.
What changed
| API | Change on 2026-10-21 | What to do |
|---|---|---|
| Messages | temperature, top_p and top_k are removed. Sending any of them returns 400 on every model | Delete them from request bodies, including default values like temperature: 1 |
| Messages | A document block placed directly in an assistant message returns 400 | Put documents in user turns or tool results |
| Messages | A text block with a non-empty citations array in a user message returns 400, directly or inside a search_result | Strip citations before you send earlier model output back as user content |
| Admin | RBAC groups drop roles; members drop group_id; roles drop name | Read role_ids, rbac_group_id, display_name |
| Admin | Rate-limit entries drop group_type; API keys drop workspace_id | Read group.type and scope.workspace_id |
| Enterprise Analytics | Usage and cost reports drop actor.email; summaries drop summaries | Read actor.email_address and data |
The Admin and Analytics changes are renames. Code that reads a removed field gets undefined rather than an error, which is worse: a dashboard quietly shows blanks. If you have scripts that list API keys or report costs, check those as carefully as your Messages calls.
Why removing temperature hurts most
temperature: 0is one of the most copied lines in LLM code. People add it to make tests "deterministic", wrappers set it by default, and config files pass it through from environment variables. On the new version, all of those requests fail with a 400, even when the value is the default.
If you relied on temperature: 0 to make tests repeatable, it never really did that. Outputs at temperature 0 could still differ between runs. Tests on model output should check structure and properties (valid JSON, required fields, a value in range) rather than exact strings. Our post on testing a model switch shows a golden-set harness that works that way.
Find what will break
# Every place your code may send a removed sampling parameter
grep -rnE "\b(temperature|top_p|top_k)\b" --include=*.{py,ts,js,mjs,go,java,cs} src/
# Every place that pins the version header by hand
grep -rn "anthropic-version" src/Expect some false positives: temperature also shows up in weather APIs and CSS. Check each hit that sits near a Claude call. Also look in config: YAML, .env files and framework settings often hold the parameter without your code ever naming it.
See the 400 for yourself
Send one request with the new header and a temperature. You get a 400 instead of a reply. Change the header back to 2023-06-01 and the same request succeeds:
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2026-10-21" \
-H "content-type: application/json" \
-d '{
"model": "claude-haiku-5-5",
"max_tokens": 64,
"temperature": 0,
"messages": [{"role": "user", "content": "Say hi"}]
}'
# Expect: HTTP 400, an invalid_request_error that names the parameterA contract test for the upgrade
This test sends the same requests on both versions. It costs a few tokens on Haiku and tells you whether the account and region you actually use behave the way the changelog says:
// Runs against both versions so you can see exactly what the upgrade changes.
import { test } from "node:test";
import assert from "node:assert/strict";
const call = (version, body) => fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": process.env.ANTHROPIC_API_KEY,
"anthropic-version": version,
"content-type": "application/json",
},
body: JSON.stringify({ model: "claude-haiku-5-5", max_tokens: 32,
messages: [{ role: "user", content: "Say hi" }], ...body }),
});
for (const param of [{ temperature: 0 }, { top_p: 0.9 }, { top_k: 40 }]) {
const name = Object.keys(param)[0];
test(`2026-10-21 rejects ${name}`, async () => {
const res = await call("2026-10-21", param);
assert.equal(res.status, 400);
const err = await res.json();
assert.equal(err.type, "error");
assert.equal(err.error.type, "invalid_request_error");
});
}
test("2026-10-21 accepts the same request without sampling params", async () => {
const res = await call("2026-10-21", {});
assert.equal(res.status, 200);
});
test("2023-06-01 still accepts temperature", async () => {
const res = await call("2023-06-01", { temperature: 0 });
assert.equal(res.status, 200);
});Run it with node --test. When it passes, you know the old version still works for a rollback and the new one rejects exactly what it should. Don't assert the exact error message text. Anthropic reserves the right to change error wording within a version, so assert the status and error.type only.
Migrating without a big bang
- Pin first. Before upgrading the SDK, set the version header yourself (or pin the old SDK major version) so the upgrade and the API version change happen in separate deploys.
- Build bodies in one place. A single function that knows which params each version allows turns a production 400 into a failing unit test:
// While you migrate: one place that builds request bodies, so the version and the
// params it allows can't drift apart.
const REMOVED_IN_2026_10_21 = ["temperature", "top_p", "top_k"];
export function messageBody(params, version = "2026-10-21") {
if (version < "2026-10-21") return params;
const leftovers = REMOVED_IN_2026_10_21.filter((k) => k in params);
if (leftovers.length) {
// Fail in your own tests, not in production with a 400.
throw new Error(`${leftovers.join(", ")} not allowed on ${version}`);
}
return params;
}- Watch 400s by version. Log the
anthropic-versionyou sent next to each 4xx. A jump ininvalid_request_errorright after a deploy tells you which service missed a parameter. - Check proxies and gateways. If a gateway sits between you and the API and injects defaults like
temperature, it breaks your requests on the new version even when your code is clean.
For the full upgrade steps, including Bedrock models older than 4.7, read Anthropic's migration guide. To practise asserting on 400 responses without spending tokens, use our practice endpoints.