◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 34 days left. If your app calls it, check the migration target●SDK 58 ISSUE — Early reports include Android widgets not refreshing on a schedule and Stripe linking statically●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 34 days left. If your app calls it, check the migration target●SDK 58 ISSUE — Early reports include Android widgets not refreshing on a schedule and Stripe linking statically●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/AI Models
◉ AI Models/2026-10-27Intermediate

Sending temperature to the Claude API Now Returns a 400 on the New Version. Finding Every Spot in Your App

Claude API version 2026-10-21 returns a 400 if you send temperature, top_p or top_k. When it hits you, a script to scan your app and SDK setup, and the order to fix things in.

Claude API14temperatureanthropic-versionSDKSupabase41Rork603

Say you added temperature: 0 to your summarizer a few months ago to keep its output steady. Today you update your dependencies, redeploy, and only the summarizer starts returning 400 errors. You didn't touch the model or the prompt.

The first suspect worth checking is the new Claude API version, 2026-10-21. Anthropic's API versioning page says this version removes temperature, top_p and top_k, and that a request sending any one of them returns a 400.

Not every app breaks today, though. Only apps that have started sending the new version do. Below is how to tell which camp yours is in, a script that finds the spots in your code, and the order I would fix things in.

It breaks the moment your app switches versions

Here is what I could confirm on the official page. There are three API versions: 2023-01-01, 2023-06-01 and 2026-10-21. Every request must carry an anthropic-version header, and if you use an official SDK, the SDK sets it for you.

So which version your app sends depends on how it calls the API.

How you call itVersion sentIf you pass temperature
Plain fetch with 2023-06-01 hard-coded in the headerThe old one, until you change itStill works today. The moment you switch the header to the new version, it returns a 400
Official SDK 0.x (for example ^0.137.0)Old version 2023-06-01Still works today
Official SDK 1.0.0 or later (TypeScript)New version 2026-10-21A 400 as soon as you send it

The third row comes from my own check, not from the official page. I pulled @anthropic-ai/sdk 0.137.0 and 1.0.0 from npm and compared them. The default header in client.js is 2023-06-01 in 0.137.0 and 2026-10-21 in 1.0.0. On npm, 1.0.0 was published on October 21, 2026, and its CHANGELOG reads "add support for new API version 2026-10-21".

One more thing that is easy to miss. Even with ^0.137.0 in package.json, a caret range on a 0.x package stays within 0.137.x, so npm update will not carry you to 1.0.0 on its own. Your app breaks on the day you decide to take the major upgrade. If you scan beforehand, that day can be uneventful.

The scan script

It has no dependencies and runs on Node.js alone. It looks for three things: temperature, top_p and top_k assignments, the value of the anthropic-version header, and the SDK version in package.json. To avoid picking up another vendor's temperature, it only reads files that contain the word anthropic or claude.

// scan-claude-api-params.mjs — find settings that return 400 on API version 2026-10-21
// Usage: node scan-claude-api-params.mjs ./my-app
import { readdirSync, readFileSync, statSync } from "node:fs";
import { join, relative, extname } from "node:path";
 
const root = process.argv[2] ?? ".";
const SKIP_DIRS = new Set(["node_modules", ".git", ".expo", "ios", "android", "dist", "build"]);
const EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".json", ".sql"]);
 
const samplingRe = /\b(temperature|top_p|top_k)\b\s*[:=]/;
const versionRe = /anthropic-version['"]?\s*[:=,]\s*['"](\d{4}-\d{2}-\d{2})['"]/i;
const sdkRe = /"@anthropic-ai\/sdk"\s*:\s*"([^"]+)"/;
const claudeRe = /anthropic|claude/i;
 
const rows = [];
function walk(dir) {
  for (const name of readdirSync(dir)) {
    if (SKIP_DIRS.has(name)) continue;
    const path = join(dir, name);
    const st = statSync(path);
    if (st.isDirectory()) { walk(path); continue; }
    if (!EXTS.has(extname(name)) || st.size > 1_000_000) continue;
    const text = readFileSync(path, "utf8");
    const rel = relative(root, path);
    const isClaudeFile = claudeRe.test(text); // only files that talk to Claude (skips other vendors' temperature)
    text.split("\n").forEach((line, i) => {
      const at = `${rel}:${i + 1}`;
      const sdk = line.match(sdkRe);
      if (sdk) rows.push({ kind: "SDK", at, note: `@anthropic-ai/sdk ${sdk[1]} (sends the new version once you are on major 1 or later)`, bad: false });
      const ver = line.match(versionRe);
      if (ver) rows.push({ kind: "VERSION", at, note: `anthropic-version ${ver[1]}${ver[1] >= "2026-10-21" ? " (affected)" : " (still on the old version)"}`, bad: false });
      const s = isClaudeFile && line.match(samplingRe);
      if (s) rows.push({ kind: "FIX", at, note: `${s[1]} is set (a 400 on 2026-10-21 just for sending it)`, bad: true });
    });
  }
}
walk(root);
 
for (const r of rows) console.log(`${r.kind} | ${r.at} | ${r.note}`);
const bad = rows.filter((r) => r.bad).length;
console.log(`\nFound ${rows.length} / need fixing: ${bad}`);
process.exit(bad > 0 ? 1 : 0);

Run it like this.

node scan-claude-api-params.mjs ./my-app

I tested it on a dummy project with five files: an Edge Function-style fetch (2023-06-01 plus temperature: 0), an SDK-based screen file (temperature and top_p), a package.json with ^0.137.0, a file that only calls another vendor's API, and the same strings inside node_modules. The run produced the following.

SDK | package.json:1 | @anthropic-ai/sdk ^0.137.0 (sends the new version once you are on major 1 or later)
FIX | src/caption.ts:3 | temperature is set (a 400 on 2026-10-21 just for sending it)
VERSION | supabase/functions/summarize/index.ts:3 | anthropic-version 2023-06-01 (still on the old version)
FIX | supabase/functions/summarize/index.ts:4 | temperature is set (a 400 on 2026-10-21 just for sending it)

Found 4 / need fixing: 2

That run also confirmed that the other vendor's file and node_modules are skipped. The exit code is 1 when anything needs fixing, so you can wire it into a pre-build check.

A few limits. It searches line by line as plain text, so options gathered into a separate file and spread in with ...options will slip through. Servers written in Python or other languages are out of scope. I would read the result as a tool for making sure that what it finds gets fixed, not as proof of safety when it prints zero.

Fix it before you change the version

Removing temperature is safe on the old version too, because you are only leaving out an argument. That gives you a clean order.

  1. Remove temperature, top_p and top_k first, and deploy on the version you are on today.
  2. Watch the output for a while.
  3. Later, take the SDK major upgrade or change the header to the new version.

The fix itself is small. Before and after:

// Before: temperature: 0 was added to keep summaries from drifting
body: JSON.stringify({ model: "claude-sonnet-5-5", max_tokens: 400, temperature: 0, messages }),
 
// After: no sampling settings; the shape is pinned in the prompt instead
body: JSON.stringify({
  model: "claude-sonnet-5-5",
  max_tokens: 400,
  system: "Write the summary in three sentences or fewer, each under 25 words.",
  messages,
}),

As an indie developer, I watch most closely the spots where temperature: 0 was standing in for "the same input always gives the same output". Once it is gone, the output will vary a little from call to call, so the receiving side needs to be built for that. If a feature expects JSON, validate the string with JSON.parse and retry once on failure. If a screen has a length limit, trim the text on the display side. Having those guards in first makes the app's behavior after the change much easier to predict.

Anthropic's page does not name a replacement setting. The more practical framing, I think, is not "what replaces it" but "make the app work without it".

Keep the model swap in a separate deploy

Claude Sonnet 4.5 is scheduled to retire from the API on November 30. I covered finding leftover model IDs in Is Your Rork App Still Calling Sonnet 4.5? Finding Out Before November 30.

One piece of advice here: do not ship the model ID change and the sampling-parameter removal in the same deploy. If a 400 or an odd-looking output appears after changing both, you cannot tell which one caused it. Ship the parameter removal first (safe on the old version), then swap the model ID the next day or later. If something goes wrong, you know where to look.

The idea of checking before a major upgrade is the same as in A Script to Find the React Native APIs SDK 58 Removed, Before You Upgrade.

A first step you can take today

Run the script once in your project folder and look at two things: the number of FIX lines, and the value on any VERSION line. If it still says 2023-06-01 and your SDK is on 0.x, nothing breaks today. If it does find something, remove just those lines and ship that change on the version you are already on.

Anthropic's pages can change. Before you actually switch, take one more look at the API versioning page.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

◉ AI Models2026-10-25
Is Your Rork App Still Calling Sonnet 4.5? Finding Out Before November 30
Claude Sonnet 4.5 is scheduled to retire from the API on November 30, 2026. A small script to find leftover model IDs in your app, and the order to fix them in depending on where they live.
◉ AI Models2026-10-20
Before You Type "Connect Supabase": The Two Values to Copy, and the One You Must Not
Rork asks for just two things before you type Connect Supabase in chat: a Publishable key and your project link. Here is where to copy them from, how to avoid pasting the secret key that sits on the same screen, and a small script that checks the values locally first.
◉ AI Models2026-10-14
Take the Prompt Out of the App: An Edge Function Gateway With the Guard on the Output Side
A system prompt shipped inside your app is readable from the day it ships. This walkthrough moves the prompt into a Supabase Edge Function, lets the client name only a task, and puts the guard on an output allowlist, with tested code.