A fresh install of LangChain, Pydantic AI or LlamaIndex now pulls anthropic 2.x. Find out which of your calls break before your next build does
None of the three frameworks puts an upper bound on the anthropic package, so any rebuild since 21 October resolves the 2.x SDK, which talks to API version 2026-10-21. We ran the latest release of each against the live API on 28 October: LangChain 1.7.7 and Pydantic AI 2.63.0 still forward temperature, and the API answers 400 'temperature: Extra inputs are not permitted'. LlamaIndex 0.12.3 fails on every call with 'Cannot instantiate typing.Union' before a request leaves the process. Here is the one-line pin for pip, uv and Dependabot, a script that tells you which calls depend on temperature (a Haiku 4.5 rewriter went from 1 distinct output in 20 to 15), the per-request escape hatch, and the gateway header check.
On 27 October the team behind GOV.UK Chat reverted a bump of the anthropic Ruby gem to 2.2.0, because every Claude call to Bedrock had started returning a 400 with the message temperature: Extra inputs are not permitted. They pinned the gem to 1.x and told Dependabot to stop proposing the major.
They saw it because Dependabot opened a pull request. Most Python projects will not get that warning, because the anthropic dependency is not theirs. It comes in through a framework, and none of the three most common ones caps it:
| Package (latest, 28 Oct) | Requires |
|---|---|
langchain-anthropic 1.7.7 | anthropic>=0.120.0 |
pydantic-ai-slim[anthropic] 2.63.0 | anthropic>=1.15.0 |
llama-index-llms-anthropic 0.12.3 | anthropic>=0.75.0 |
anthropic 2.0.0 went to PyPI on 21 October and 2.3.0 is current. A clean pip install of any of the three, run today, resolves anthropic 2.3.0. That covers every Docker image, CI job and serverless deploy that installs without a lockfile.
What the 2.x SDK changes on the wire
We pointed anthropic 1.17.0 (the last 1.x) and 2.3.0 at a local server that logs request headers. Same script, same call:
Anthropic/Python 1.17.0 X-Api-Key: sk-ant-... anthropic-version: 2023-06-01
Anthropic/Python 2.3.0 Authorization: Bearer sk-ant-... anthropic-version: 2026-10-21
Both changes are documented in the migration guide for API version 2026-10-21. The one that breaks working code is in its breaking-changes list: on 2026-10-21, a request that sends temperature, top_p or top_k "returns a 400 error, even at the parameter's default value." We checked that directly against the API with claude-haiku-4-5: temperature: 0 and temperature: 1.0 both return 400 on the new version and both succeed on 2023-06-01.
The Python SDK no longer accepts temperature as an argument at all (1.17.0 already raises TypeError for it), so code that calls the SDK directly fails loudly on your own machine. Frameworks are different. They keep their own temperature setting and put it into the request body themselves, where nothing checks it until the API does.
What each framework does with 2.3.0
We installed each package fresh, let it resolve anthropic 2.3.0, and called claude-haiku-4-5 on the live API:
- LangChain 1.7.7 (released 27 October):
ChatAnthropic(temperature=0)fails withAnthropicInvalidRequestError: Error code: 400 ... 'temperature: Extra inputs are not permitted'. Withouttemperatureit works. - Pydantic AI 2.63.0 (released 28 October):
model_settings={"temperature": 0.0}fails withModelRequestRejectedError: status_code: 400and the same message. Without it, it works. Pydantic AI already fixed the 2.x type change on 22 October; the temperature forwarding is a separate problem. - LlamaIndex 0.12.3: every call fails with
TypeError: Cannot instantiate typing.Union, with or withouttemperature, and no request is sent. The integration builds messages by callingMessageParam(...), which 2.x turned into a union of three role types (the migration guide lists this). The bug is open as #23701 with a fix in review.
LlamaIndex has a second catch on 1.x. Its Anthropic class defaults to temperature=0.1 and only removes the setting for models on its own list of models that reject it (Opus 4.7 and later, Fable 5, Sonnet 5 and others). On anthropic 1.17.0, claude-haiku-4-5 raises TypeError: ... unexpected keyword argument 'temperature' from that default, while claude-haiku-5-5 works. You never set a temperature, and the default fails on its own.
On TypeScript the exposure is smaller. @langchain/anthropic 1.6.0 depends on @anthropic-ai/sdk ^0.129.0, and npm's caret on a 0.x version only allows patch releases, so it cannot reach 1.x. A package.json with >= or * for the SDK does resolve 1.3.0. npm ls @anthropic-ai/sdk shows what you have.
Step 1: see what your next build will install
In the environment you deploy from:
pip show anthropic | grep -E '^(Version|Required-by)'
Required-by: langchain-anthropic tells you a framework brought it in. With uv, uv pip tree --invert --package anthropic prints the same chain. If the version starts with 2 and nothing is failing yet, your calls happen not to send a sampling parameter. That is worth confirming in Step 3 rather than assuming.
Step 2: pin the major until you have decided
Each of these was run on a fresh environment with langchain-anthropic and resolved anthropic 1.17.0.
With pip, a constraints file pins a package you do not depend on directly, without adding it to your requirements:
echo 'anthropic<2' > constraints.txt
pip install -r requirements.txt -c constraints.txt
With uv, in pyproject.toml:
[tool.uv]
constraint-dependencies = ["anthropic<2"]
If Dependabot manages the repo, stop it from opening the major bump, as GOV.UK Chat did, in .github/dependabot.yml under the pip ecosystem entry:
ignore:
- dependency-name: anthropic
update-types: ["version-update:semver-major"]
The pin is safe to leave in place for weeks. It changes nothing about how your requests behave today.
Step 3: find out which calls depend on temperature
Dropping temperature everywhere is the obvious fix, and it changes behavior on any model that accepts other values. The migration guide is explicit: on a model such as Sonnet 4.6, a request that lowered temperature "loses that effect. No other setting replaces it." Claude 4.7 and later models already accept only the default, so on those, removing the parameter changes nothing.
Start with the places that set it, including framework configuration:
grep -rnE "temperature|top_p|top_k" --include='*.py' .
Then measure the ones on older models. This script runs one of your prompts ten times as it is sent today and ten times with temperature removed. It runs on anthropic 2.x, using the per-request escape hatch described below:
from collections import Counter
import anthropic
MODEL = "claude-haiku-4-5" # the model this call uses in production
TEMPERATURE = 0 # the value your code sets today
PROMPT = open("prompt.txt").read()
client = anthropic.Anthropic()
def run(**extra):
r = client.messages.create(model=MODEL, max_tokens=200,
messages=[{"role": "user", "content": PROMPT}], **extra)
return r.content[0].text.strip()
today = Counter(run(extra_headers={"anthropic-version": "2023-06-01"},
extra_body={"temperature": TEMPERATURE}) for _ in range(10))
after = Counter(run() for _ in range(10))
print(f"with temperature={TEMPERATURE}: {len(today)} distinct outputs of 10")
print(f"temperature removed: {len(after)} distinct outputs of 10")
for text, n in after.most_common():
print(f" {n}x {text[:100]}")
Two prompts on Haiku 4.5 show why it is worth running per call. A ticket classifier that answers with one of four labels returned billing in all ten runs either way, so that call can drop the parameter. A query rewriter that turns the last turn of a conversation into a standalone search query returned one string in 20 runs at temperature=0, and 15 different strings in 20 runs without it. One of them read tax filing requirements when relocating from Spain for a user who had moved to Spain. A rewriter feeding a search index or a cache key cannot absorb that.
Step 4: keep the calls that need it on the old version
The guide's answer for a request that relies on a non-default temperature is to stop sending the parameter, or to keep that request on 2023-06-01. On anthropic 2.3.0, both header and body can be set per request:
client.messages.create(
model="claude-haiku-4-5", max_tokens=200, messages=messages,
extra_headers={"anthropic-version": "2023-06-01"},
extra_body={"temperature": 0},
)
The same works through the frameworks by setting the header on the client they use. Both of these returned 200 with temperature=0 on 2.3.0:
# LangChain
ChatAnthropic(model="claude-haiku-4-5", temperature=0,
default_headers={"anthropic-version": "2023-06-01"})
# Pydantic AI
from anthropic import AsyncAnthropic
from pydantic_ai.providers.anthropic import AnthropicProvider
provider = AnthropicProvider(anthropic_client=AsyncAnthropic(
default_headers={"anthropic-version": "2023-06-01"}))
Treat this as a holding position for calls that are moving to a Claude 4.7 or later model anyway, not as a permanent setting. On Amazon Bedrock it is the only position available for older models: the guide says 2026-10-21 is available there only for Claude 4.7 and later, so a Bedrock call to Sonnet 4.5 or Haiku 4.5 stays on the 1.x SDK. That is the reason GOV.UK Chat gives for pinning instead of removing temperature.
Step 5: check the gateway before you upgrade
The 2.x SDK sends the key as Authorization: Bearer. The Claude API accepts either header. A proxy, gateway, log filter or test stub that reads X-Api-Key sees no key at all. Send your gateway the new form directly:
curl -s -o /dev/null -w "%{http_code}\n" "$GATEWAY_URL/v1/messages" \
-H "Authorization: Bearer $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2026-10-21" -H "content-type: application/json" \
-d '{"model":"claude-haiku-4-5","max_tokens":8,"messages":[{"role":"user","content":"ok"}]}'
200 means it reads the new header. Anything in the 401 or 403 range means the gateway needs changing first, or the client has to move the key back into X-Api-Key; the guide has a snippet for each SDK. Python clients that pass both api_key and auth_token now raise ValueError at construction, which you will see on the first run.
The order that avoids a 400 in production
Pin first, so nothing upgrades by accident. Measure the calls that set temperature, and split them into ones that can drop it and ones that need 2023-06-01 for now. Check the gateway. Then lift the pin, with the type checker run once, since the 2.x types change MessageParam and remove betas from the non-beta Models methods.
The habit underneath all of this applies to any SDK: a framework that lists a provider SDK without an upper bound hands that provider's next major release to your build server on the day it ships. A constraints file is the one place where you can see and control that. Related reading: why temperature=0 was already failing on newer models, what changes when a Haiku 4.5 classifier moves to Haiku 5.5, and the temperature entry in the glossary.
Get the next post when it ships
One email on Sunday with the new post and a short list of what shipped that week — new guides, tool updates, and a couple of links worth reading.