claude update bails out on false-positive npm-global detection when npm prefix == native install bin dir

Resolved 💬 6 comments Opened Apr 26, 2026 by qdddddd Closed Jun 18, 2026

Summary

claude update aborts with a "Multiple installations found" warning that fires as a false positive when the user's npm prefix happens to equal the parent of the native-install launcher (~/.local). The suggested remediation (npm -g uninstall @anthropic-ai/claude-code) is a no-op because the npm package is not actually installed. The updater never proceeds to check the remote channel, so the user is silently pinned to whatever native version is currently symlinked.

Environment

  • OS: Linux (Ubuntu, kernel 6.8)
  • Shell: zsh
  • Claude Code: 2.1.119 (native build)
  • Install layout: native binaries under ~/.local/share/claude/versions/, launcher symlink at ~/.local/bin/claude
  • npm prefix: /home/qdu/.local (set in ~/.npmrc) — i.e. npm-prefix/bin == native-launcher dir
  • ~/.local/lib/node_modules/ does not contain @anthropic-ai/claude-code — npm package is genuinely absent. Other npm-global packages (codex-activator, neovim, @openai, tree-sitter-cli) live there.

Reproduction

$ which claude
~/.local/bin/claude

$ ls -la /home/qdu/.local/bin/claude
lrwxrwxrwx ... ~/.local/bin/claude -> ~/.local/share/claude/versions/2.1.119

$ npm config get prefix
~/.local

$ ls ~/.local/lib/node_modules/ | grep claude
(empty)

$ claude update
Current version: 2.1.119
Checking for updates to latest version...

Warning: Multiple installations found
- npm-global at ~/.local/bin/claude
- native at ~/.local/bin/claude (currently running)

Warning: Leftover npm global installation at ~/.local/bin/claude
Fix: Run: npm -g uninstall @anthropic-ai/claude-code 
$ echo $?
0

The output ends there — the updater never reports the remote latest version or whether an update is available.

What was tried (none of which work)

  1. npm -g uninstall @anthropic-ai/claude-code — returns up to date in 22ms, exit 0. No-op. Subsequent claude update produces the identical warning.
  2. claude install latest — succeeds, but "latest" resolves to the version already installed (2.1.119 in this case). Symlink mtime updates, target unchanged.
  3. claude install 2.1.120 — a binary at ~/.local/share/claude/versions/2.1.120 exists locally (apparently pre-downloaded). Command reports ✔ Claude Code successfully installed! Version: 2.1.120 but the ~/.local/bin/claude symlink still points to 2.1.119. So the install command silently fails to swap the launcher when this detector trips.
  4. NPM_CONFIG_PREFIX=/tmp/npm-temp-claude claude update — gets past the warning (no "Multiple installations" output), but then hangs indefinitely at Checking for updates to latest version.... Killed after ~5 minutes; no further output, no network or filesystem activity visible in /proc/<pid>/fd.

Likely root cause

The npm-global detector appears to flag any claude binary located at $(npm config get prefix)/bin/claude, regardless of whether the npm package metadata (node_modules/@anthropic-ai/claude-code) exists. When the user's npm prefix is ~/.local (a common choice for non-root npm setups), the path collision is unavoidable because the native launcher also lives at ~/.local/bin/claude.

Suggested fixes

  1. The npm-global check should require the actual npm package to be present (e.g. node_modules/@anthropic-ai/claude-code/package.json), not just a binary at the prefix's bin path.
  2. claude install <version> should bypass the npm-global guard (since the user has explicitly named a version) and update the launcher symlink unconditionally.
  3. The hang under NPM_CONFIG_PREFIX override is a separate issue worth investigating — the updater appears to depend on more than just npm config get prefix to make forward progress.

Workaround for affected users

None that is non-disruptive. Moving npm prefix off ~/.local requires reinstalling all other npm-global packages. Manually re-pointing the launcher works for a known new version (ln -sfn ~/.local/share/claude/versions/<new> ~/.local/bin/claude) but is not discoverable.

View original on GitHub ↗

This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗