TL;DR Run
claude doctorfrom your shell and readLast update attempt. If it sayssuccessand your version never moves, you have your own launcher at~/.local/bin/claude: delete it and runclaude update. If you installed with npm, the global directory isn't writable. If it saysconnection dropped, the download died. And ifConfig install methoddoesn't saynative, there was never an auto-update to fail.
You get auto update failed at startup, or Claude Code is simply not updating: weeks without a new feature and claude --version stuck on the same number. The update is not working and nothing tells you why.
Claude Code checks for a new version on startup and periodically while it runs. It downloads and installs in the background, and the new version takes effect the next time you open a session. When that fails it tells you, but it doesn't tell you why.
The result of the last attempt is stored, though, and one command prints it.
claude doctor
Claude Code doctor
Running: native (2.1.237)
Path: /Users/juan/.local/share/claude/versions/2.1.237
Config install method: native
Auto-updates: enabled
Auto-update channel: latest
Last update attempt: success → 2.1.236 (2026-08-19)
No installation issues found.
Three lines carry the whole diagnosis: Config install method, Auto-updates and Last update attempt. Between them they separate the four causes.
1. It says success, but your version never changes
This is the confusing one: the update reports success, claude --version stays put, and you haven't seen a new feature in weeks.
On macOS and Linux the native installer manages ~/.local/bin/claude as a symlink into ~/.local/share/claude/versions/. If you ever replaced it with a script of your own or pointed it somewhere else, both auto-update and claude update leave it alone: new versions still install under versions/, but your launcher decides which one actually runs. claude doctor flags a launcher the native installer didn't create.
which -a claude
ls -la ~/.local/bin/claude
If that doesn't resolve into a versions/ directory, hand control back:
rm ~/.local/bin/claude
claude update
A custom launcher also means Claude Code keeps every installed version on disk, because it can't tell which one you need.
2. You installed with npm and the global directory isn't writable
When the npm global directory can't be written to, the background update has nowhere to land. Claude Code shows a one-time notice at startup, and claude doctor lists the fixes it can offer.
The clean way out is the native installer, which installs under your own home directory:
curl -fsSL https://claude.ai/install.sh | bash
Don't reach for sudo npm install -g to get around it. And if you try to fix things by reinstalling through npm, you can hit ENOTEMPTY: directory not empty while npm moves the old package aside. The npm error path line names the directory at fault:
rm -rf "$(npm root -g)/@anthropic-ai/claude-code"
rm -rf "$(npm root -g)/@anthropic-ai/.claude-code-"*
npm install -g @anthropic-ai/claude-code
3. The download died
The connection dropped while downloading the update
Download timed out: exceeded the total deadline
Literal, and the mildest of the four. Check your connection and try again. If it happens every time, the docs point you at your network configuration, which is where a corporate proxy or a firewall usually sits.
4. There was never an auto-update
If Config install method doesn't say native, nothing failed: Homebrew, WinGet, apt, dnf and apk don't update themselves. This is where brew upgrade claude-code is not working, and it's almost always because these are two separate casks: claude-code follows the stable channel and claude-code@latest follows latest. Upgrade the one you actually installed, not the other.
To have Claude Code run the upgrade for you on Homebrew and WinGet, add this to your settings.json:
{
"env": {
"CLAUDE_CODE_PACKAGE_MANAGER_AUTO_UPDATE": "1"
}
}
On WinGet it can fail while Claude Code is running, because Windows locks the executable. apt, dnf and apk still need a manual upgrade because those commands require elevated privileges. The full map by install method lives in the how to update Claude Code tip.
Force the update now
claude update
Current version: 2.1.237
Checking for updates to latest version...
Claude Code is up to date (2.1.237)
When it does install something it reports Successfully updated from <old version> to version <new version>. Installs managed by Homebrew, WinGet or apk report Claude is up to date! instead.
Turning auto-update off on purpose
If you'd rather decide when the new version lands:
{
"env": {
"DISABLE_AUTOUPDATER": "1"
}
}
DISABLE_AUTOUPDATER only stops the background check; claude update and claude install still work. To block every path, manual included, use DISABLE_UPDATES. Watch for the side effect: freezing Claude Code freezes your plugins too, so add FORCE_AUTOUPDATE_PLUGINS=1 if you want your marketplaces to keep refreshing.
Reference
| What to read or set | For |
|---|---|
Last update attempt |
The result of the last attempt, with version and date |
Config install method |
Whether your install auto-updates at all |
Auto-updates / Auto-update channel |
Whether it's on, and on which channel (latest or stable) |
claude update |
Force the update now, on any install method |
DISABLE_AUTOUPDATER=1 |
Stop only the background check |
DISABLE_UPDATES=1 |
Block every update path |
CLAUDE_CODE_PACKAGE_MANAGER_AUTO_UPDATE=1 |
Auto-update through Homebrew and WinGet |
Official docs: Auto-updates
Pairs well with
/doctorinside the session, which also fixes what it finds.- Is Claude Code down, for when the problem isn't your install.