[BUG] `claude install <channel>` removes working npm-global install even when the new native install isn't reachable on PATH (cleanup gated on PATH-detection that's already informational only)
Preflight Checklist
- [x] I have searched existing issues. The original filing #59034 was closed by github-actions[bot] on 2026-06-13 for 30-day inactivity, not because the bug was fixed. This refile updates the report against current CC versions and tightens the fix proposal to the load-bearing change.
- [x] This is a single bug report.
- [x] Reproduced on Claude Code through 2.1.177.
What's Wrong?
Running claude install <channel> (e.g. stable or latest) on a working npm-global Claude Code installation can leave the user with no functional claude binary on $PATH. The subcommand attempts to switch the install method from npm-global to the native installer; cleanupNpmInstallations() runs after the native install attempt regardless of whether the native install is actually reachable from the invoking user's shell environment.
The install command already detects the PATH problem and prints a warning (verified at the binary level on 2.1.148 and the 2.1.177 wire). The warning is informational only: cleanup proceeds anyway. The result is a state where the new binary exists on disk but isn't reachable from any shell.
Definitive reproduction
Reproduces cleanly in a fresh node:20 container with a single-user ~/.npm-global prefix (the common setup that avoids sudo npm install -g):
docker run -it --rm node:20 bash -c '
mkdir -p ~/.npm-global && npm config set prefix ~/.npm-global && export PATH=~/.npm-global/bin:$PATH
npm install -g @anthropic-ai/claude-code@stable && claude --version
echo === about to claude install stable ===
claude install stable
echo === after claude install stable, no hash -r yet ===
claude --version || echo FAILED with cached path
echo === after hash -r ===
hash -r
claude --version || echo STILL FAILED
echo === final state ===
ls -la ~/.local/bin/claude ~/.local/share/claude/ ~/.npm-global/bin/claude 2>&1
'
Output (abbreviated):
✔ Claude Code successfully installed!
Version: 2.1.128
Location: ~/.local/bin/claude
⚠ Setup notes:
● Native installation exists but ~/.local/bin is not in your PATH. Run:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> your shell config file && source your shell config file
=== after claude install stable, no hash -r yet ===
bash: line 7: /root/.npm-global/bin/claude: No such file or directory
FAILED with cached path
=== after hash -r ===
bash: line 10: claude: command not found
STILL FAILED
=== final state ===
ls: cannot access '/root/.npm-global/bin/claude': No such file or directory
lrwxrwxrwx 1 root root 42 May 14 12:20 /root/.local/bin/claude -> /root/.local/share/claude/versions/2.1.128
The detection fires; the warning prints; the cleanup runs anyway; the user is left with neither install reachable on $PATH.
Two severity tiers
~/.local/binalready on$PATH(most modern interactive systems): bash's hash cache shows a phantom "No such file or directory" error pointing at the now-removed npm-global path. Recovery ishash -ror a new shell. Annoying but the install is functionally fine.~/.local/binNOT on$PATH(Node containers, minimal/server installs, some fresh user setups): genuine no-binary-reachable state. Recovery requires either following CC's own PATH-add suggestion ANDhash -r/new shell, OR reinstalling via npm-global.
In both cases, the npm-global install that was the working binary the user invoked the install command from is removed despite the new install not being immediately usable.
Why this matters
- Anthropic's own messaging treats
claude installas the canonical migration path going forward. Strings in the production binary (verified through 2.1.177) include the recommendation to runclaude installto migrate from npm to native. Users following that guidance hit this break. - Single-user-prefix npm setups are common for users who set
npm config set prefix ~/.npm-globalto avoidsudo. The native installer's PATH expectations may not match this setup, increasing the rate at which the switch fails to leave a usable binary. - Failure mode is silent at the time of failure.
claude installexits with✔ Claude Code successfully installed!even when the new install isn't reachable. The user only discovers the broken state on next CC invocation. - Recovery requires user knowledge the failure mode doesn't surface. A non-technical user looking at the "Native installation exists but ~/.local/bin is not in your PATH" warning may not connect it to the disappeared
claudecommand on their next attempt.
Suggested fix
The PATH-not-found detection that already runs should gate the cleanup step rather than being informational only:
- If
cleanupNpmInstallations()is about to run AND the post-install reachability check found the new install isn't on the invoking user's$PATH, skip the cleanup. Emit a clear message:
> Native installation in place at ~/.local/bin/claude but not on $PATH. Keeping npm-global install at <old path> until you add ~/.local/bin to $PATH and re-run claude install.
- If the new install IS reachable on
$PATH, the cleanup is safe to run, but the user's shell hash cache still needs invalidation. Either suggesthash -r/ new shell in the success message, or have the cleanup step touch a marker that bash's hashtable will detect on next lookup.
The first half (gate cleanup on reachability) is the load-bearing fix. The second half (hash-cache UX) is polish.
Adjacent context
- Original filing: #59034 (closed by github-actions[bot] on 2026-06-13 after 30 days inactivity, not because the bug was fixed).
- Triggered an erratum on a vsits.co blog post in the same family (install advice corrected to lead with
npm install + jqsettings-edit rather thanclaude install). - Related class of "silent install/migration failure where the warning is informational only": worth a structural look at the install subcommand's stop-conditions more broadly.
Environment
- Reproduced on Claude Code 2.1.128 (original report), 2.1.148 (current pinned on visits-01), and the install-string path is unchanged through 2.1.177 (current
lateston npm). - Linux (Node 20 container; also observed on Ubuntu)
- npm-global with
npm config set prefix ~/.npm-global
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗