{"slug": "anthropic-python-sdk-v1-0-what-breaks-and-how-to-migrate", "title": "Anthropic Python SDK v1.0: What Breaks and How to Migrate", "summary": "Anthropic released the Python SDK v1.0 on August 20, 2026, moving the HTTP layer to httpx2, requiring Python 3.10+, and removing long-deprecated features including the legacy Text Completions API and sampling parameters from Messages methods. The SDK removal of temperature, top_p, and top_k coincides with seven current Claude models rejecting any non-default sampling value with a 400 error, while the Messages API still accepts them via extra_body on older models. Teams on Python 3.9 must pin anthropic==0.125.0, and the Bedrock client now raises an error at startup if no AWS region is configured.", "body_md": "The Anthropic Python SDK v1.0 landed on August 20, 2026, and the [release-notes entry](https://platform.claude.com/docs/en/release-notes/overview) is blunt about what it is: the HTTP layer moves from httpx to httpx2, the package now requires Python 3.10 or later, and a set of long-deprecated surface is removed outright — the legacy Text Completions API, the `temperature`\n\n, `top_p`\n\nand `top_k`\n\nparameters on Messages methods, and the tool runner’s client-side `compaction_control`\n\n.\n\nThe easy compression of that list is “Anthropic removed sampling controls.” It did not. The Messages API reference still documents and accepts all three parameters, and the SDK ships a documented workaround. What actually changed is one layer deeper: seven current Claude models reject any non-default sampling value with a 400 regardless of how the request reaches them. The SDK removal lands alongside that model-level rule, and the workaround only buys you anything on older models. That distinction is the whole story, and this guide leads with it.\n\nBelow: what shipped and what did not (this is Python only), the sampling split by model, a migration matrix with before-and-after code for every breaking change in the SDK’s own [MIGRATION.md](https://github.com/anthropics/anthropic-sdk-python/blob/main/MIGRATION.md), the one change that can break a running agent loop with nothing raised, the instrumentation that quietly stops seeing your Anthropic calls alongside it, the Bedrock construction that now fails at startup instead, and a real hold-back pin for teams that cannot move today.\n\n- 01This is a Python-only event.anthropic 1.0.0 was uploaded to PyPI on August 20, 2026 and the v1.0.0 GitHub tag was published the same day. The TypeScript SDK’s GitHub Releases show v0.120.0 (Aug 19) as newest with no v1.0.0 tag. The last 0.x Python release, v0.125.0, went out on August 19 and is the hold-back pin.\n- 02httpx2 is a maintained, API-compatible fork — not an official successor.Anthropic’s release notes and SDK docs both use fork language. httpx2 is stewarded by Pydantic Services Inc. Build custom http_client, Timeout and transport objects from httpx2, and call httpx2.alias_httpx() at startup if tracing or mocking libraries patch httpx directly.\n- 03Sampling parameters left the SDK signatures, not the API.temperature, top_p and top_k are gone from messages.create(), messages.stream() and messages.parse(). The Messages API reference still accepts them, and extra_body is the documented path. But seven current models return a 400 on any non-default value, thinking on or off, so extra_body only helps on older models.\n- 04Two changes fail quietly; the Bedrock one fails at startup.Tool-runner compaction moved from a client-side kwarg to a server-side beta (context_management with betas=['compact-2026-01-12'], trigger at 50,000 input tokens or more) — a loop that simply drops the old argument keeps running and raises nothing. The httpx2 move is the other quiet one: tracing and mocking libraries that patch httpx by module name keep patching a module the SDK no longer uses unless you call alias_httpx(). AnthropicBedrock is the loud one — it now raises an error when no AWS region is configured instead of silently using us-east-1, so it announces itself the moment the client is constructed.\n- 05The floor is Python 3.10, and the 0.x line is your only 3.9 path.PyPI metadata for anthropic 1.0.0 lists Requires-Python >=3.10 with classifiers for 3.10 through 3.14. If a service is stuck on 3.9, pin anthropic==0.125.0 (or anthropic>=0.125,<1) and schedule the runtime upgrade before the SDK upgrade.\n\n## 01 — What ShippedA 1.0 that is a *deprecation gate*, not a feature drop.\n\nThe v1.0.0 tag on [anthropic-sdk-python](https://github.com/anthropics/anthropic-sdk-python/releases) was published on August 20, 2026 at 19:58 UTC, and its Conventional-Commits body is almost comically short: a single BREAKING CHANGES line pointing at the httpx2 upgrade and “some minor breaking changes,” a bug fix that stops the helpers warning about `output_format=`\n\n, and a chore restoring the original streaming-event imports. Everything of substance lives in MIGRATION.md, which the release notes name as the canonical source “for every change with before-and-after snippets.”\n\nRead the timing alongside the last 0.x release and the shape of the event becomes clear. v0.125.0 went out on August 19 at 22:00 UTC — less than a day earlier — carrying managed-agents web-search configuration and self-hosted-sandbox memory-store support, none of it migration-related. v1.0 adds no comparable capability. It is the moment Anthropic chose to cash in a backlog of deprecations at once, which is exactly what a major version is for under the SemVer policy in Anthropic’s own [Python SDK docs](https://platform.claude.com/docs/en/cli-sdks-libraries/sdks/python): the package “generally follows SemVer,” with the caveat that some backward-incompatible type-only or internal changes may ship as minor versions.\n\nThree scope notes matter before you touch anything. First, this is the Python `anthropic`\n\npackage only. The TypeScript SDK’s [GitHub Releases](https://github.com/anthropics/anthropic-sdk-typescript/releases) show `v0.120.0`\n\n(August 19) as the newest entry and no `v1.0.0`\n\ntag exists there. Second, it is separate from the Aug-19 wave that moved computer use, browser use, the Files API, Agent Skills and Admin API user management to GA — [our post on that GA wave covers it](/blog/claude-platform-betas-ga-computer-use-files-skills) and nothing in it is restated here. Third, this is not Claude Code, which has its own changelog and version line.\n\n##### Up from 3.9\n\nPyPI metadata for anthropic 1.0.0 lists Requires-Python >=3.10, with classifiers for Python 3.10, 3.11, 3.12, 3.13 and 3.14 — five supported minors. The 0.x line remains the only path for 3.9 services.\n\n##### Last 0.x release\n\nPublished August 19 at 22:00 UTC, under 24 hours before v1.0.0. Still installable from PyPI. Pin it if you cannot migrate today, and treat the pin as a dated exception with an owner.\n\n##### Optional extras on 1.0.0\n\naiohttp, aws, bedrock, google-cloud, mcp, vertex and webhooks. The base package still ships five platform client classes, including the AnthropicBedrock class whose region behaviour changed.\n\nAnthropic’s own install line for the new major is `pip install --upgrade \"anthropic>=1,<2\"`\n\n. The upper bound is the point: it lets you take future 1.x releases without being carried into a future 2.0 by a loose constraint. The rest of this post assumes you are deciding whether to run that command this week or pin and schedule it.\n\n## 02 — SDK vs APISampling parameters: the *decisive* distinction.\n\nHere is the sentence that is easiest to get wrong. MIGRATION.md removes `temperature`\n\n, `top_p`\n\nand `top_k`\n\nfrom the typed method signatures of `messages.create()`\n\n, `messages.stream()`\n\nand `messages.parse()`\n\n. The [Messages API reference](https://platform.claude.com/docs/en/api/messages) still lists all three as optional number fields with full descriptions — defaults, ranges, the nucleus-sampling explanation. Nothing on that page says they were removed from the API. The SDK dropped the parameters; the wire protocol did not.\n\nThe documented escape hatch is `extra_body`\n\n, and MIGRATION.md gives the before-and-after itself:\n\n```\n# Before (0.x): typed keyword argument\nmessage = client.messages.create(\n    model=MODEL,\n    max_tokens=1024,\n    temperature=0.2,\n    messages=[{\"role\": \"user\", \"content\": \"Summarise this contract.\"}],\n)\n\n# After (1.x): pass it through to the request body\nmessage = client.messages.create(\n    model=MODEL,\n    max_tokens=1024,\n    extra_body={\"temperature\": 0.2},\n    messages=[{\"role\": \"user\", \"content\": \"Summarise this contract.\"}],\n)\n```\n\nSo far, an SDK-only story, and the release notes give it a one-line rationale: v1.0 “removes long-deprecated surface.” What makes it more than a signature change sits in a different document entirely. The [Thinking docs](https://platform.claude.com/docs/en/build-with-claude/thinking)’ “Limits and feature compatibility” section — evergreen reference documentation describing the current model line, not an August 20 announcement — states the model-level rule that makes the workaround moot for most production traffic:\n\nPut the two documents together and the picture is exact. **Seven current models hard-reject any non-default sampling value, through the SDK, through raw HTTP, with thinking on or off.** On those models, `extra_body={\"temperature\": 0.2}`\n\nproduces the same 400 the typed argument would have. There, the SDK removal takes away nothing the API would have honoured — the typed surface and the model behaviour now agree. `extra_body`\n\nexists for the older models where sampling is still honoured, and for default values everywhere. The table below is that rule extracted into something you can scan.\n\n| Model | temperature | top_p | top_k | Non-default value sent |\n|---|---|---|---|---|\n| Current models · hard 400, thinking on or off | ||||\n| Claude Fable 5 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |\n| Claude Mythos 5 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |\n| Claude Mythos Preview | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |\n| Claude Opus 5 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |\n| Claude Opus 4.8 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |\n| Claude Opus 4.7 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |\n| Claude Sonnet 5 | Default only | Default only | Default only | 400 error on every request, regardless of transport or thinking state |\n| Older models · restriction applies only while thinking is on | ||||\n| Older models, thinking on | Incompatible with thinking | Allowed between 0.95 and 1 | Incompatible with thinking | temperature / top_k rejected; top_p accepted only inside the 0.95–1 band |\n| Older models, thinking off | Accepted as documented | Accepted as documented | Accepted as documented | Honoured per the Messages API reference — reach it via `extra_body` in SDK 1.x |\n\nThe practical consequence for a migration: grep your codebase for the three parameter names before you upgrade, and sort each hit by the model it targets. Hits against the seven current models were already failing or were sitting at default values — delete them. Hits against older models move to `extra_body`\n\n, with a comment naming the model dependency, because the moment that call is repointed at a current model it becomes a 400 in production. Teams that went through [our Opus 4.6 to 4.7 migration playbook](/blog/claude-opus-4-6-to-4-7-migration-playbook-breaking-changes-2026) will recognise the shape: the model boundary, not the SDK boundary, is where sampling assumptions break.\n\n## 03 — Migration MatrixEvery breaking change, with its *scope* and its fallback.\n\nMIGRATION.md documents each change but never says whether it is confined to the SDK or reflects something at the API or model layer. That column is the synthesis this table adds. “SDK-only” means a raw HTTP caller is unaffected; “SDK + model” means the behaviour you hit is enforced below the SDK; “client to server” means a capability moved rather than disappeared; “SDK client removed” means the typed wrapper is gone and MIGRATION.md does not state what the underlying endpoint does. The last column is the minimum action if you pin to 0.125.0 instead of migrating.\n\n| What broke | Scope | Before (0.x) | After (1.x) | If you pin to 0.125.0 |\n|---|---|---|---|---|\n| Transport and runtime | ||||\n| HTTP layer | SDK-only | import httpx | import httpx2 as httpx or httpx2.alias_httpx() at startup | Nothing now; audit every lib that patches httpx (respx, pytest-httpx, OpenTelemetry, Sentry) before you migrate |\n| Python floor | SDK-only | Python >= 3.9 | Python >= 3.10 | Pin is the only 3.9 path; schedule the runtime upgrade first |\n| Transport / proxy types | SDK-only | anthropic.Transport anthropic.ProxiesTypes | httpx2.BaseTransport httpx2.Proxy | Find-and-replace when you migrate; no runtime risk before |\n| Removed surface | ||||\n| Text Completions | SDK client removed | client.completions.create(...) HUMAN_PROMPT / AI_PROMPT | client.messages.create(...) | Highest-pressure item: port to Messages now, migrate SDK after |\n| temperature / top_p / top_k | SDK + model | messages.create(..., temperature=0.2) | messages.create(..., extra_body={\"temperature\": 0.2}) — older models only | Seven current models already 400 on non-default values; delete or default those calls regardless of SDK version |\n| output_format schema dict | SDK-only | output_format=SCHEMA_DICT | output_config={\"format\": SCHEMA_DICT} (helpers take types only for output_format=) | Move dict schemas to output_config ahead of time; types keep working |\n| messages.parse(stream=True) | SDK-only (never worked) | messages.parse(..., stream=True) | messages.stream(..., output_format=Type) stream.get_final_message().parsed_output | None — MIGRATION.md says it crashed on 0.x too |\n| isinstance(obj, Stream) shim | SDK-only | isinstance(obj, Stream) | from anthropic.lib.streaming import MessageStream isinstance(obj, MessageStream) | Switch the check early; MessageStream is the right type on both lines |\n| Raw HTTP body= bytes | SDK-only | client.post(..., body=b\"...\") | client.post(..., content=b\"...\") | Rename when you migrate |\n| Behaviour changes | ||||\n| Tool-runner compaction | Client to server | compaction_control={\"enabled\": True, \"context_token_threshold\": 100_000} | betas=[\"compact-2026-01-12\"], context_management={\"edits\": [...]} trigger >= 50,000 input tokens | Re-test any long agent loop on the server-side path before migrating; this one fails quietly |\n| AnthropicBedrock region | SDK-only | AnthropicBedrock() silently used us-east-1 | AnthropicBedrock(aws_region=\"...\") or AWS_REGION / AWS_DEFAULT_REGION / boto3 profile | Set the region explicitly today — it documents the intent and is a no-op on 0.x |\n| Bedrock unknown stream events | SDK-only | amazon-bedrock-invocationMetrics yielded | Unknown events skipped, not yielded | If you read invocation metrics off the raw stream, that consumer needs a new source |\n| Async raw responses | SDK-only | response.parse() response.text / response.content | await response.parse() response.text() / response.read() | Wrap raw-response access in one helper so the await lands in one place |\n| HTTP headers | SDK-only | Case-sensitive names; bytes values tolerated | Case-insensitive names; bytes values raise | Decode header values to str now |\n| Renames | ||||\n| Type aliases | SDK-only | BetaBase64PDFBlockParam agent_toolset.READ_MAX_BYTES | BetaRequestDocumentBlockParam agent_toolset.DEFAULT_MAX_FILE_BYTES | Rename when you migrate |\n\nFifteen rows, and only one of them — sampling — is enforced at the model layer. One more, compaction, moved to a server-side beta rather than vanishing. That ratio is the reassuring part of the release. It also tells you where to spend review time: the “Behaviour changes” rows deserve a test each, and so does the HTTP-layer row, because the changes that fail quietly give you nothing to grep for, while the renames and the removed-surface rows announce themselves at import or at the first call. The sections below take them in turn.\n\n## 04 — Transporthttpx to httpx2: a fork with *careful* wording.\n\nMIGRATION.md explains the transport move in one line: the SDK’s HTTP layer moved from httpx, “which is no longer actively maintained,” to httpx2. The [httpx2 project on PyPI](https://pypi.org/project/httpx2/) is stewarded by Pydantic Services Inc., whose [pydantic/httpx2 repository](https://github.com/pydantic/httpx2) hosts the fork, with original-author continuity from Tom Christie, httpx’s creator, and its current release at the time the SDK shipped was 2.12.0 from August 18 — two days earlier. The PyPI description is explicit about the motive: “With HTTPX itself seeing limited activity recently, Pydantic is picking up stewardship under the HTTPX2 name so that users have a reliably maintained path forward — including timely security updates.”\n\nNotice what Anthropic does not say. Neither the release notes nor the SDK docs call httpx2 “the official successor” or claim an endorsement from the httpx maintainers. The release notes say “a maintained, API-compatible fork”; the SDK docs page, in its “Configuring the HTTP client” section, independently says “an API-compatible fork of httpx.” Neither phrase carries an endorsement, and that restraint is the accurate version — it is the one to repeat in your change ticket.\n\n\"The SDK sends requests with httpx2, an API-compatible fork of httpx.\"— Claude Platform docs, Python SDK page, “Configuring the HTTP client”\n\nFor most codebases the change is invisible, because the default client is built for you and the `DefaultHttpxClient`\n\nhelpers are unchanged. You have work to do in two situations: you construct your own `http_client`\n\n, `Timeout`\n\nor transport objects from httpx, or you run tracing or mocking libraries that patch httpx by module name.\n\n``` python\n# Before (0.x): custom client built from httpx\nimport httpx\nfrom anthropic import Anthropic\n\nclient = Anthropic(\n    http_client=httpx.Client(proxy=\"http://proxy.internal:3128\"),\n    timeout=httpx.Timeout(60.0),\n)\n\n# After (1.x), option A: build the same objects from httpx2\nimport httpx2 as httpx\nfrom anthropic import Anthropic\n\nclient = Anthropic(\n    http_client=httpx.Client(proxy=\"http://proxy.internal:3128\"),\n    timeout=httpx.Timeout(60.0),\n)\n\n# After (1.x), option B: make plain `import httpx` resolve to httpx2.\n# Call this once at process startup, before any library imports httpx.\nimport httpx2\n\nhttpx2.alias_httpx()\n```\n\nOption B is the one that matters for observability and test suites. MIGRATION.md names the category — libraries that patch httpx directly — and the usual suspects are `respx`\n\n, `pytest-httpx`\n\n, OpenTelemetry’s `HTTPXClientInstrumentor`\n\nand Sentry’s httpx integration. Without the alias, those tools keep instrumenting a module the SDK no longer uses, and the failure mode is silent: tests pass against a mock that never fires, traces stop showing Anthropic spans, and nobody gets an exception. Put `httpx2.alias_httpx()`\n\nin the same bootstrap that configures tracing, and add one test that asserts an Anthropic call appears in your span exporter.\n\n`aiohttp`\n\nas an opt-in alternative via `DefaultAioHttpClient`\n\nfor higher async concurrency, and that path did not change in v1.0. If you already run on aiohttp, the httpx2 move touches you only where you import httpx types directly — *check your type hints and test fixtures, not your request path*.\n\n## 05 — Removed SurfaceText Completions and the *3.10* floor.\n\nThe loudest removal is the legacy Text Completions client. `client.completions.create()`\n\n— the SDK’s wrapper for the `/v1/complete`\n\nendpoint — is gone, and so are the `anthropic.HUMAN_PROMPT`\n\nand `anthropic.AI_PROMPT`\n\nconstants that built its prompt strings. Any module that still imports them fails at import time on 1.x, which at least makes this the easiest break to find. The fix is the port to Messages that has been the documented path for a long time.\n\n``` python\n# Before (0.x): legacy Text Completions\nfrom anthropic import AI_PROMPT, HUMAN_PROMPT, Anthropic\n\nclient = Anthropic()\ncompletion = client.completions.create(\n    model=MODEL,\n    max_tokens_to_sample=300,\n    prompt=f\"{HUMAN_PROMPT} Summarise this contract.{AI_PROMPT}\",\n)\ntext = completion.completion\n\n# After (1.x): Messages\nfrom anthropic import Anthropic\n\nclient = Anthropic()\nmessage = client.messages.create(\n    model=MODEL,\n    max_tokens=300,\n    messages=[{\"role\": \"user\", \"content\": \"Summarise this contract.\"}],\n)\ntext = message.content[0].text\n```\n\nThe Python floor is the quieter removal, and the one with the longest lead time. MIGRATION.md states it plainly — “The minimum supported Python version has increased from 3.9 to 3.10” — and [PyPI’s metadata for anthropic 1.0.0](https://pypi.org/project/anthropic/1.0.0/) confirms it independently with `Requires-Python: >=3.10`\n\nand classifiers for 3.10 through 3.14 only. A pip resolver on a 3.9 interpreter will simply refuse to select 1.0.0, which is polite, but it also means a service that pins `anthropic`\n\nloosely on 3.9 will stay on 0.x forever without telling anyone. Add an explicit upper bound so the intention is visible in the lockfile.\n\n##### Upgrade now\n\nFor services already on Python 3.10+, on Messages, with no custom httpx objects and no client-side compaction. Run the test suite, check tracing spans, ship.\n\n##### Pin, then schedule\n\nFor services on Python 3.9, still calling completions.create(), or depending on client-side compaction_control. The pin is the last 0.x release and stays installable; give it an owner and a date.\n\n##### Automated edit pass\n\nMIGRATION.md notes that Claude Code users can run this command for automated edits. Treat the output as a first draft — it is a helper for the SDK migration, not part of the SDK, and the review burden stays with you.\n\n## 06 — Tool RunnerCompaction moved *server-side*; it did not disappear.\n\nThis is the change most likely to break a running agent loop without raising anything. On 0.x, the tool runner accepted a client-side `compaction_control`\n\nargument that compacted context locally once a token threshold was crossed. On 1.x that argument is removed, and the replacement is the server-side `context_management`\n\nfeature behind the `compact-2026-01-12`\n\nbeta. Same job, different layer, and one new constraint: MIGRATION.md notes the trigger threshold must be at least 50,000 tokens.\n\n```\n# Before (0.x): client-side compaction\nrunner = client.beta.messages.tool_runner(\n    model=MODEL,\n    max_tokens=4096,\n    tools=TOOLS,\n    messages=history,\n    compaction_control={\"enabled\": True, \"context_token_threshold\": 100_000},\n)\n\n# After (1.x): server-side context management (beta)\nrunner = client.beta.messages.tool_runner(\n    model=MODEL,\n    max_tokens=4096,\n    tools=TOOLS,\n    messages=history,\n    betas=[\"compact-2026-01-12\"],\n    context_management={\n        \"edits\": [\n            {\n                \"type\": \"compact_20260112\",\n                \"trigger\": {\"type\": \"input_tokens\", \"value\": 100_000},\n            }\n        ]\n    },\n)\n```\n\nWhy it fails quietly: a loop that relied on local compaction and simply drops the argument keeps running, keeps accumulating context, and only surfaces a problem when it hits a context limit or a cost alarm many turns later. Two checks catch it. First, an integration test that drives a loop past the old threshold and asserts the compaction edit appears in the response. Second, a config lint that refuses any trigger value below 50,000 — the floor is documented, and a threshold copied over from an old client-side config can sit below it, which was fine locally and is rejected server-side now.\n\nIf your agent loop lives in the Claude Agent SDK rather than in the Python SDK’s tool runner, this section does not apply to you directly — [the Agent SDK has its own migration playbook](/blog/claude-agent-sdk-migration-playbook-from-claude-code-sdk-2026), and [our production-patterns guide](/blog/claude-agent-sdk-production-patterns-guide) covers context management on that side.\n\n## 07 — BedrockAnthropicBedrock stops *guessing* your region.\n\nOn 0.x, constructing `AnthropicBedrock`\n\nor `AsyncAnthropicBedrock`\n\nwith no region configured silently fell back to `us-east-1`\n\n. On 1.x, MIGRATION.md documents that the same construction raises a `ValueError`\n\ninstead. The resolution order is explicit: an `aws_region=`\n\nconstructor argument first, then the `AWS_REGION`\n\nor `AWS_DEFAULT_REGION`\n\nenvironment variables, then the boto3 profile configuration. If none of those yields a region, the client refuses to start.\n\nThe SDK docs frame this class carefully: `AnthropicBedrock`\n\nis retained for existing applications on the Bedrock `InvokeModel`\n\npath, while `AnthropicBedrockMantle`\n\nis the recommended class for new Bedrock projects. The region change is about the legacy class, which is precisely the one most likely to be sitting in an older service with a minimal constructor call.\n\n##### Pass aws_region explicitly\n\nAnthropicBedrock(aws_region=\"eu-central-1\"). Highest precedence, visible in code review, and a harmless no-op on 0.x — so it is safe to land before the SDK upgrade.\n\n##### AWS_REGION or AWS_DEFAULT_REGION\n\nSecond in the resolution order. Right when the same image runs in several regions and the deployment layer already owns the variable. Verify it reaches the process, not just the shell.\n\n##### Lean on the shared AWS config\n\nLowest precedence. Works on developer machines with a configured profile and fails on a clean CI runner — which is the environment where the new ValueError will find you first.\n\n##### Check who reads *raw events*\n\nUnknown Bedrock stream events are now skipped rather than yielded; MIGRATION.md calls out amazon-bedrock-invocationMetrics specifically. Any dashboard fed from that event needs a new source.\n\nThe design call is the right one. A client that quietly routes production traffic to a region nobody chose is a data-residency incident waiting for an auditor, and the old default made that the path of least resistance. The cost is a one-time startup failure in any environment that relied on it — which is why the explicit constructor argument is worth landing this week even if the SDK upgrade itself waits.\n\n## 08 — Smaller BreaksAsync raw responses, headers, and the *structured-output* rename.\n\nThe remaining changes are mechanical, but two of them hide in code that runs rarely. On the async client, `.with_raw_response`\n\nresults now require `await response.parse()`\n\nwhere 0.x allowed a synchronous `.parse()`\n\n. The `.text`\n\nand `.content`\n\nproperties on raw responses became methods — `response.text()`\n\nand `response.read()`\n\n— and the response gains directly accessible `json()`\n\n, `iter_bytes()`\n\n, `iter_text()`\n\nand `iter_lines()`\n\n.\n\n```\n# Before (0.x): async raw response\nresponse = await client.messages.with_raw_response.create(**params)\nmessage = response.parse()\nrequest_id = response.headers.get(\"request-id\")\nbody = response.text\n\n# After (1.x)\nresponse = await client.messages.with_raw_response.create(**params)\nmessage = await response.parse()\nrequest_id = response.headers.get(\"Request-Id\")  # names are case-insensitive now\nbody = response.text()\n```\n\nHeaders are the second quiet one. Names are now case-insensitive, which is a loosening, but raw `bytes`\n\nvalues now raise and must be decoded to `str`\n\nfirst — a tightening that lands on whichever middleware stuffs a signed token into a header without decoding it. Structured output is the third: passing a raw schema dict as `output_format=`\n\nis removed from message methods in favour of `output_config={\"format\": {...}}`\n\n, and the `parse()`\n\n, `stream()`\n\nand `count_tokens()`\n\nhelpers accept only types for `output_format=`\n\n. Finally, `messages.parse(stream=True)`\n\nis gone, which MIGRATION.md notes “never worked” — use `messages.stream()`\n\nwith `output_format=`\n\nand read `stream.get_final_message().parsed_output`\n\n.\n\nNone of these justify delaying the migration on their own. They do justify running the migration on a branch with the full test suite, rather than bumping the version in a dependency-update bot and merging on green, because raw-response code and header middleware are exactly the paths most suites do not exercise.\n\n## 09 — Hold-Back PinPin to 0.125.0 or migrate: a *decision*, not a default.\n\nThe hold-back pin is a real, currently installable version, not a guess: `anthropic==0.125.0`\n\n, the last 0.x release, published on August 19 and still on PyPI. The looser form `anthropic>=0.125,<1`\n\ndoes the same job while leaving room for any further 0.x uploads. Either way, a pin is a dated exception with an owner, and the table below is the decision behind it: the symptom that forces the pin, the pin itself, how much pressure sits behind the deadline, and what changes when you do migrate.\n\n| Symptom | Recommended pin | Deadline pressure | What changes when you migrate |\n|---|---|---|---|\n| Service is still on Python 3.9 | anthropic==0.125.0 | High — the 0.x line is the only SDK path for 3.9, and it receives no 1.x features or fixes | Runtime moves to 3.10+ first; the SDK upgrade follows in the same change window |\n| Still calling client.completions.create() | anthropic>=0.125,<1 | Highest — this surface was long-deprecated before v1.0 removed the client | Port to messages.create(); prompt strings built from HUMAN_PROMPT / AI_PROMPT become message arrays |\n| Agent loop depends on client-side compaction_control | anthropic>=0.125,<1 | Medium — nothing breaks on 0.x, but the capability now lives server-side behind a beta | betas=[\"compact-2026-01-12\"] plus context_management with a trigger of 50,000 input tokens or more |\n| Relying on AnthropicBedrock’s old us-east-1 default | No pin needed | Low — set the region explicitly today; it is a no-op on 0.x and required on 1.x | Construction raises ValueError until aws_region, AWS_REGION / AWS_DEFAULT_REGION, or a boto3 profile supplies a region |\n| Sending non-default temperature / top_p / top_k | No pin helps | Already failing on the seven current models; model-level, not SDK-level | Delete or default the values for current models; move older-model calls to extra_body with a comment naming the dependency |\n\nThe last row is the one to internalise. Pinning protects you from SDK-level changes; it does nothing for a behaviour the model enforces. That is the general lesson of a 1.0 like this one, and it maps onto the framework in [our API versioning decision matrix](/blog/api-versioning-strategies-2026-engineering-decision-matrix): a client library’s major version is a contract about the typed surface, and the typed surface can be narrower than the wire protocol or wider than what a given model honours. When the three disagree, the model wins, and your tests should be written against the model.\n\nLooking forward, the direction of travel is not hard to read. Anthropic’s typed surface and the sampling restriction on its current models now agree, the Agent SDK and Codex CLI have both been through their own config migrations this summer — [Codex’s was a config-schema move](/blog/codex-cli-rust-migration-playbook-config-changes-2026) rather than a transport swap — and the pattern across vendors is that SDK majors are increasingly the place where deprecations get enforced rather than announced. The teams that cope best keep a single adapter module around each vendor client, so the next major touches one file. If you are building or operating agentic systems on Claude and want that adapter layer designed before the next migration rather than during it, our [AI transformation engagements](/services/ai-transformation) start with exactly that audit, and our [web development team](/services/web-development) handles the runtime and dependency upgrades that usually come bundled with it.\n\n## 10 — ConclusionMigrate the behaviour changes *deliberately*; the rest is find-and-replace.\n\n### The SDK’s typed surface and the models’ sampling rules now agree — the real work is in the behaviour changes, not the renames.\n\nAnthropic Python SDK v1.0 is a deprecation gate. The HTTP layer moves to httpx2, “a maintained, API-compatible fork” in Anthropic’s own careful wording; the floor rises to Python 3.10; Text Completions, the sampling parameters and client-side compaction leave the typed surface; AnthropicBedrock refuses to guess a region. Fifteen documented changes, and *only one is enforced by the models themselves* — sampling, where seven current models already return a 400 on any non-default value regardless of how the request arrives.\n\nThe migration itself is an afternoon for a service that is on Python 3.10+, on Messages, and not building its own httpx objects. It is a planned change for anyone running a long agent loop on client-side compaction, instrumenting httpx by module name, or constructing `AnthropicBedrock`\n\nwithout a region. The first two break with nothing raised at all; the third refuses to construct the client, which is loud but lands at startup in whichever environment relied on the old default. Land the region argument and the `alias_httpx()`\n\ncall first; both are safe on 0.x.\n\nIf you cannot move this week, `anthropic==0.125.0`\n\nis a real pin with a real date, and it buys you time on everything except sampling. Give it an owner, and write the tests that matter against the model rather than the SDK — because that is the boundary this release just made visible.", "url": "https://wpnews.pro/news/anthropic-python-sdk-v1-0-what-breaks-and-how-to-migrate", "canonical_source": "https://www.digitalapplied.com/blog/anthropic-python-sdk-v1-breaking-change-migration", "published_at": "2026-08-20 00:00:00+00:00", "updated_at": "2026-08-23 10:43:30.124960+00:00", "lang": "en", "topics": ["developer-tools", "ai-products", "artificial-intelligence"], "entities": ["Anthropic", "Python SDK v1.0", "httpx2", "Pydantic Services Inc.", "Claude", "AnthropicBedrock", "PyPI", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/anthropic-python-sdk-v1-0-what-breaks-and-how-to-migrate", "markdown": "https://wpnews.pro/news/anthropic-python-sdk-v1-0-what-breaks-and-how-to-migrate.md", "text": "https://wpnews.pro/news/anthropic-python-sdk-v1-0-what-breaks-and-how-to-migrate.txt", "jsonld": "https://wpnews.pro/news/anthropic-python-sdk-v1-0-what-breaks-and-how-to-migrate.jsonld"}}