Upgrade the SDK
What Upgrading Means
Upgrading the SDK means replacing the installed version of the anthropic package with a newer release from PyPI. Anthropic releases new versions frequently. Each one adds support for new models and API features, fixes bugs, or improves performance.
Before upgrading, you need to understand what kind of release you are moving to, because some upgrades are routine and others require code changes.
Understanding Version Numbers
SDK versions follow the MAJOR.MINOR.PATCH pattern of Semantic Versioning (SemVer):
2 . 4 . 1
│ │ └── PATCH: bug fixes; no new features
│ └──────── MINOR: new features, backward-compatible
└────────────── MAJOR: breaking changes are allowed
| Upgrade type | Example | What to expect | Risk |
|---|---|---|---|
| Patch | 2.4.0 → 2.4.1 | Bug fixes | Very low |
| Minor | 2.4.1 → 2.5.0 | New features and new models; existing code keeps working | Low |
| Major | 1.x → 2.0.0 | Breaking changes; code may need updates | Requires review and testing |
The SDK's Own Versioning Rules
The SDK generally follows SemVer, with one documented caveat. Certain backward-incompatible changes can appear in minor releases when they:
- affect only static types, not runtime behavior;
- change library internals that are technically public but not meant for external use; or
- are not expected to affect the vast majority of users in practice.
In practice, minor upgrades are safe for normal code that uses documented features. Code that relies on private attributes (names starting with _, other than the documented _request_id) can break at any time.
SDK Major Versions and API Versions
Each SDK major version is tied to one API version, sent in the anthropic-version header (Lessons 1 and 2):
| SDK version | API version sent |
|---|---|
| Before 2.0.0 | 2023-06-01 |
| 2.0.0 and later | 2026-10-21 |
A major SDK upgrade can therefore also change the API behavior your code receives, not just the Python interface. That is the main reason major upgrades need deliberate testing.
Why Upgrade, and Why Not Blindly
Reasons to upgrade:
- New models and features. New request parameters and response types arrive in new SDK releases. Older versions may not know about them.
- Bug fixes and security fixes, in the SDK and in its dependencies.
- Compatibility with documentation. Official examples are written for the current SDK.
Reasons to upgrade deliberately, not automatically:
- A major version can remove parameters or change behavior.
- Your application's behavior should change only when you have tested the change.
- Production systems must match the versions you tested.
The goal is regular, controlled upgrades: routine for minor and patch versions, planned for major versions.
Check Your Current Version
From the Terminal
python -m pip show anthropic
Name: anthropic
Version: 1.8.0
...
From Python
import anthropic
print(anthropic.__version__)
Find Out Whether Newer Versions Exist
List all outdated packages in the environment:
python -m pip list --outdated
Package Version Latest Type
--------- ------- ------ -----
anthropic 1.8.0 2.0.0 wheel
List every available version of the SDK:
python -m pip index versions anthropic
Note:
pip indexis marked experimental by pip, but it is widely used and works with current pip versions. You can also check the release history on the package's PyPI page or the GitHub repository's releases.
Upgrade with pip
Upgrade to the Latest Version
python -m pip install --upgrade anthropic
--upgrade (short form -U) tells pip to replace the installed version with the newest compatible release. Without it, pip install anthropic does nothing when any version is already installed.
By default, pip upgrades the SDK's dependencies only if the new SDK version requires it. Other packages in your environment are left alone.
Upgrade Within a Major Version
To get all minor and patch updates but not the next major version:
python -m pip install --upgrade "anthropic>=2.0,<3"
This is the safe routine-upgrade command for a project on SDK 2.x.
Install an Exact Version
python -m pip install "anthropic==2.0.0"
Verify
python -c "import anthropic; print(anthropic.__version__)"
Update Your Requirements File
Upgrading the environment does not change requirements.txt. If you use frozen versions, regenerate the file:
python -m pip freeze > requirements.txt
If you use ranges, edit the range by hand, for example from anthropic>=1.0,<2 to anthropic>=2.0,<3. Then commit the change, so every machine and deployment uses the same version.
Upgrade with Other Tools
uv
uv lock --upgrade-package anthropic # Update the lock file to the newest allowed version
uv sync # Install the locked versions into .venv
To move to a new major version, change the constraint:
uv add "anthropic>=2.0,<3"
Poetry
poetry update anthropic # Newest version allowed by the constraint
poetry add anthropic@latest # Change the constraint to the latest release
Jupyter
%pip install --upgrade anthropic
Then restart the kernel. A running kernel has already imported the old version and keeps using it until restarted.
Upgrading Across a Major Version: 1.x to 2.0.0
Version 2.0.0 is the first SDK release that uses API version 2026-10-21. It includes breaking changes in both the API and the SDK. If your code was written for 1.x, check each item below.
1. temperature, top_p, and top_k Are Removed
API version 2026-10-21 rejects these sampling parameters, even at their default values, and SDK 2.x no longer has them.
# SDK 1.x: worked
message = client.messages.create(
model="claude-opus-5-5",
max_tokens=500,
temperature=0.2,
messages=[{"role": "user", "content": "Summarize this report."}],
)
# SDK 2.x: remove the parameter
message = client.messages.create(
model="claude-opus-5-5",
max_tokens=500,
messages=[{"role": "user", "content": "Summarize this report."}],
)
Without these parameters, requests use the default sampling behavior. Models that already accept only the defaults (Claude 4.7 and later) behave exactly as before. On older models that accepted other values, code that lowered temperature for more consistent output loses that effect, and no other setting replaces it. If a workload truly depends on a non-default value, it must stay on SDK 1.x (API version 2023-06-01) for now.
2. The API Key Is Sent as Authorization: Bearer
SDK 2.x sends the key as Authorization: Bearer <key> instead of in the X-Api-Key header. The Claude API accepts either, so ordinary code needs no change.
It matters if anything in your infrastructure reads X-Api-Key, such as a proxy, API gateway, logging filter, middleware, or test stub. Update those components to read Authorization. Alternatively, follow the migration guide's instructions for moving the key back to X-Api-Key with a custom HTTP client.
Per-request key overrides also change:
# SDK 1.x
extra_headers={"X-Api-Key": other_key}
# SDK 2.x
extra_headers={"Authorization": f"Bearer {other_key}"}
3. A Client Holds Exactly One Credential
Passing more than one credential, such as both api_key and auth_token, now raises ValueError:
client = Anthropic(api_key=key, auth_token=token) # SDK 2.x: ValueError
Pass only one. When none is passed, the client uses the first credential it finds, starting with ANTHROPIC_API_KEY (Lesson 7).
4. MessageParam Is Now a Union of Role-Specific Types
Messages written as dictionaries need no change:
messages = [{"role": "user", "content": "Hello"}] # Works in 1.x and 2.x
Code that called MessageParam like a constructor must change, because that now raises TypeError:
from anthropic.types import MessageParam
# SDK 1.x
message = MessageParam(role="user", content="Hello")
# SDK 2.x
message: MessageParam = {"role": "user", "content": "Hello"}
MessageParam still works as a type annotation, as in list[MessageParam]. The new role-specific types are UserMessageParam, AssistantMessageParam, and SystemMessageParam.
5. betas Moved from client.models to client.beta.models
# SDK 1.x
page = client.models.list(betas=["some-beta"])
# SDK 2.x
page = client.beta.models.list(betas=["some-beta"])
6. The License Changed to Apache 2.0
SDK 2.x is licensed under Apache License 2.0. Earlier versions remain under MIT. No code changes are needed, but update your dependency-license records if your organization tracks them.
7. Amazon Bedrock Caveat
On Amazon Bedrock, API version 2026-10-21 is available only for Claude 4.7 and later models. If you call older models through Bedrock, stay on your current SDK version for those calls until you move to a newer model.
Note: If you are upgrading from a 0.x release, there is an additional set of breaking changes from 0.x to 1.x, described in the v1 migration guide (
MIGRATION.md) in the SDK's GitHub repository. Upgrade one major version at a time, and test after each step.
The complete, authoritative list is in the official guide, Migrating to API version 2026-10-21, in the Claude Platform documentation. Always read it before a major upgrade.
Practical Example: Scanning Your Code Before a Major Upgrade
Before upgrading from 1.x to 2.x, it helps to find every place in your code that the breaking changes might affect. This script scans a project for the patterns described above:
"""scan_for_v2_changes.py: find code that may need updates for anthropic 2.x."""
import re
import sys
from pathlib import Path
# Each pattern maps to an explanation of what to change.
CHECKS = {
r"\btemperature\s*=": "temperature is removed in 2.x: delete the argument",
r"\btop_p\s*=": "top_p is removed in 2.x: delete the argument",
r"\btop_k\s*=": "top_k is removed in 2.x: delete the argument",
r"MessageParam\(": "MessageParam can no longer be called: use a dict literal",
r"models\.(list|retrieve)\([^)]*betas": "betas moved: use client.beta.models",
r"[Xx]-[Aa]pi-[Kk]ey": "the SDK now sends Authorization: Bearer, not X-Api-Key",
r"auth_token\s*=": "check that each client receives only one credential",
}
SKIP_DIRS = {".venv", "venv", ".git", "__pycache__", "node_modules"}
def scan(root: Path) -> int:
findings = 0
for path in root.rglob("*.py"):
if SKIP_DIRS.intersection(path.parts) or path.name == Path(__file__).name:
continue
lines = path.read_text(encoding="utf-8", errors="ignore").splitlines()
for line_number, line in enumerate(lines, start=1):
for pattern, advice in CHECKS.items():
if re.search(pattern, line):
findings += 1
print(f"{path}:{line_number}: {advice}")
print(f" {line.strip()}")
return findings
if __name__ == "__main__":
project_root = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(".")
total = scan(project_root)
print(f"\n{total} potential issue(s) found.")
Run it from your project folder:
python scan_for_v2_changes.py .
Example output:
app/summarizer.py:14: temperature is removed in 2.x: delete the argument
temperature=0.3,
app/proxy.py:22: the SDK now sends Authorization: Bearer, not X-Api-Key
api_key = request.headers.get("X-Api-Key")
2 potential issue(s) found.
How the Script Works
CHECKSmaps regular expressions to advice. For example,\btemperature\s*=matchestemperature=ortemperature =as a whole word (\b), so it finds keyword arguments but not unrelated words that merely contain "temperature".root.rglob("*.py")walks the project recursively and yields every Python file.SKIP_DIRSexcludes the virtual environment and other generated folders. Without this, the script would scan the SDK's own source code inside.venvand report hundreds of irrelevant matches. The script also skips its own file, whose patterns would otherwise match themselves.errors="ignore"prevents a crash on files with unusual encodings.- For each match, the script prints the file, line number, advice, and the line itself, the familiar
path:lineformat that most editors and terminals turn into clickable links.
The script reports potential issues. A match can be a false positive, such as a variable named temperature in a weather app. Review each finding instead of changing code blindly.
A Safe Upgrade Workflow
For a minor or patch upgrade:
- Upgrade in your development environment (
pip install --upgrade "anthropic>=2.0,<3"). - Run your tests and try the main features.
- Update
requirements.txtor the lock file, and commit. - Deploy.
For a major upgrade, add preparation and review:
- Read the migration guide and release notes for the new major version.
- Create a Git branch for the upgrade.
- Scan the code for affected patterns, as in the script above.
- Upgrade the package and update the version constraint.
- Fix each breaking change, then run the full test suite.
- Test against the real API in a development or staging workspace, because API behavior changes too.
- Check infrastructure: proxies, gateways, and log filters that read headers.
- Deploy, and monitor errors,
stop_reasonvalues, and token usage after release.
Rolling Back
If an upgrade causes problems, reinstall the previous version:
python -m pip install "anthropic<2" # Back to the latest 1.x
python -m pip install "anthropic==1.8.0" # Or an exact known-good version
Then restore the previous requirements.txt or lock file from Git. This is easy because the old versions were recorded.
Common Mistakes
Upgrading the Wrong Environment
What happens: pip install --upgrade anthropic reports success, but anthropic.__version__ still shows the old version.
Why: the upgrade went into a different Python installation than the one running your code.
Fix: activate the project's virtual environment and use python -m pip. Confirm with pip show anthropic that the Location is inside .venv.
Not Restarting Running Processes
What happens: the package is upgraded, but a running web server, worker, or Jupyter kernel keeps the old behavior.
Why: Python imports a module once, when the process starts. Upgrading the files on disk does not change modules already loaded in memory.
Fix: restart the server, worker, or kernel after upgrading.
Upgrading Without Updating the Requirements File
What happens: your machine runs 2.x, but the deployed application still installs 1.x from requirements.txt, or the reverse.
Fix: treat the requirements file as the source of truth. Update it in the same commit as any code changes the upgrade requires.
Unbounded Version Constraints in Production
What happens: requirements.txt contains just anthropic, with no version. A routine deployment silently installs a new major version, and features break.
Fix: use a range that blocks the next major version (anthropic>=2.0,<3), or pin exact versions with a lock file.
Skipping the Migration Guide for a Major Version
What happens: code that sends temperature fails, or a proxy that expects X-Api-Key rejects every request.
Fix: read the migration guide before every major upgrade, and test against the real API before deploying.
Best Practices
- Upgrade minor and patch versions regularly, for example monthly, to stay current with models, features, and fixes.
- Plan major upgrades as a separate task with a branch, the migration guide, a code scan, and testing.
- Constrain the major version in your dependency file (
>=2.0,<3), and pin exact versions or use lock files for deployments. - Upgrade one major version at a time (0.x → 1.x → 2.x) and test after each step.
- Restart every process that uses the SDK after upgrading.
- Log
anthropic.__version__at application startup, so logs show exactly which SDK version produced a given behavior. - Use official documentation for your version. When behavior differs from the documentation, check
anthropic.__version__first.
Exercise
- Run
python -m pip list --outdatedin your tutorial environment. Is the SDK up to date? - Install an older 2.x release with an exact version specifier, verify the version, then upgrade back to the newest 2.x release with a range that blocks 3.x.
- Create a file containing
client.messages.create(..., temperature=0.5, ...)and a call toMessageParam(role="user", content="Hi"). Runscan_for_v2_changes.pyand confirm that both are reported. - Rewrite both lines so they are compatible with SDK 2.x.
Step 2:
python -m pip install "anthropic==2.0.0"
python -c "import anthropic; print(anthropic.__version__)" # 2.0.0
python -m pip install --upgrade "anthropic>=2.0,<3"
python -c "import anthropic; print(anthropic.__version__)" # newest 2.x release
Step 4:
from anthropic.types import MessageParam
# temperature removed
message = client.messages.create(
model="claude-opus-5-5",
max_tokens=200,
messages=[{"role": "user", "content": "Hi"}],
)
# dict literal instead of calling MessageParam
first_message: MessageParam = {"role": "user", "content": "Hi"}