[BUG] : fresh native installation raise warning about npm
Open 💬 19 comments Opened Oct 16, 2025 by S1M0N38
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
I've removed Claude code and related files entirely from my computer (macOS 26).
Then I've installed Claude code using
curl -fsSL https://claude.ai/install.sh | bash
So I'm expecting a clean single installation, but when running claude doctor, I get
claude doctor
Diagnostics
└ Currently running: native (2.0.19)
└ Path: /Users/simo/.local/bin/claude
└ Invoked: /Users/simo/.local/share/claude/versions/2.0.19
└ Config install method: native
└ Auto-updates enabled: default (true)
└ Search: OK (bundled)
Warning: Multiple installations found
└ npm-global at /Users/simo/.local/bin/claude
└ native at /Users/simo/.local/bin/claude
Warning: Leftover npm global installation at /Users/simo/.local/bin/claude
Fix: Run: npm -g uninstall @anthropic-ai/claude-code
Press Enter to continue…
The file at /Users/simo/.local/bin/claude is a symlink to the /Users/simo/.local/share/claude/versions/2.0.19, however Claude doctor thinks that this is a NPM installation. I think this is a bug.
What Should Happen?
No warning
Error Messages/Logs
Steps to Reproduce
describe above
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.0.19
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other
Additional Information
_No response_
19 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Claude Code's claude update command incorrectly identifies Homebrew cask
installations as npm global installations. When both native and Homebrew
cask are installed, it warns about a "leftover npm global installation" at
/opt/homebrew/bin/claude and suggests running npm -g uninstall
@anthropic-ai/claude-code, but no npm package exists. The detection logic
should check if the path is actually an npm installation versus a Homebrew
cask symlink.
Then when I run claude doctor:
Diagnostics
└ Currently running: native (2.0.36)
└ Path: /Users/***/.local/bin/claude
└ Invoked: /Users/*/.local/share/claude/versions/2.0.36
└ Config install method: native
└ Auto-updates: false
└ Search: OK (bundled)
Warning: Multiple installations found
└ npm-global at /opt/homebrew/bin/claude
└ native at /Users/***/.local/bin/claude
Warning: Leftover npm global installation at /opt/homebrew/bin/claude
Fix: Run: npm -g uninstall @anthropic-ai/claude-code
I've fixed this by removing homebrew install of claude. But still thought you all might want to know.
Confirming FLGAI's Report: Homebrew Cask Misdetected as npm-global
I can confirm the same issue that FLGAI reported above. The Homebrew cask installation is incorrectly identified as an npm global installation.
My Environment
brew install --cask claude-codeThe Issue
Running
claude doctorshows:However:
npm list -gconfirms no Claude Code package installed via npmbrew listshowsclaude-codeis installed as a cask/opt/homebrew/bin/claudeis a symlink to/opt/homebrew/Caskroom/claude-code/2.0.31/claudeThe suggested fix (
npm -g uninstall @anthropic-ai/claude-code) has no effect because there's no npm installation.Correct Fix
This properly removes the Homebrew cask installation and resolves the warning.
Root Cause
The detection logic appears to misidentify any installation in
/opt/homebrew/binas npm-global, without distinguishing Homebrew cask installations. This is a common scenario since the Homebrew cask's own documentation warns:Anyone who originally installed via
brew install --cask claude-codewill eventually end up with this dual-installation state as the auto-updater creates the native installation.Suggested Fix
The
/doctorcommand should check the actual installation type (perhaps by runningbrew listor checking if the path is inCaskroom) before suggesting the fix command.This is the closest to what I am seeing. Our installation process installs Claude Code by curling the install shell script through bash and installs some managed settings. After installation,
claude doctorreports a Multiple installations found error:As mentioned in this issue, there is not a NPM installation. In fact,
/Users/.../.local/bin/claudeis a symlink to the native version that the installer installed.The difference is that I do not have claude installed via homebrew or npm. The only copy is the one created (and symlinked) by install.sh. Another interesting note is that our NPM configuration would install claude into ~/.local/bin. I'm not sure if claude is looking at the npm config and noticing that the executable matches what npm would install and deciding that there is a duplicate or not.
Hopefully some additional breadcrumbs will help.
I verified that claude code is looking at the NPM configuration. If the NPM
prefixoption is set to~/.localthen claude code will always report multiple installations. This can be reproduced by:npm config set --location user prefix=$HOME/.localclaude doctor+1 Same issue on Fedora Linux with Claude Code 2.0.76. My npm prefix is set to
~/.local, which matches the native installation path.npm list -g @anthropic-ai/claude-codeshows empty - the package isn't there.I had reviewed my config and I also had the npm configure to follow XDG spec:
Maybe Claude doctor is checking if
claudeis found inwhich in my case is also where the native version is installed.
---
The current workaround that I'm using is to change the
npm config prefixlocation to be something different from$HOME/.local(for example to$HOME/.local/share/npm)Then manually delete
claudefrom$HOME/.local/binand reinstallclaudewith native installation.⚠️ This could break the installation of other
npmpackage that have been installed globally (i.e. using the-gflag). Delete those package from$HOME/.local/binand reinstall them (they will be installed into the new location, i.e.$HOME/.local/share/npm/binwith libs in$HOME/.local/share/npm/libs⚠️---
I've implement this workaround a couple of weeks ago, so Idk if this issue persist in recent
claude codeversions. Since then I'm on native and updatedclaudewithclaude update.My native
claudebinary is managed via MacPorts, and it's not in~/.local/bin, butclaude doctorstill incorrectly thinks it's installed via NPM:Root Cause Found: Orphaned Daemon Process from Previous Installation
After extensive debugging, I found the actual root cause of the persistent
installMethodreset.The Problem
When switching from npm-local to native installation, background claude processes from the old installation continue running. These orphaned processes periodically reset
~/.claude.jsonback toinstallMethod: "local"and recreate~/.claude/local.In my case, I had an 8-day-old daemon process (adopted by systemd --user) that was originally started from
~/.claude/local/claude. This process kept resetting my config even after I:installMethodto"native"~/.claude/localDetection
Check if you have orphaned processes from the old installation:
Look for any process with
_=.../.claude/local/claude— those are zombies from the old npm-local installation.Fix
Worth noting that ~/.local is npm's own recommended prefix for avoiding sudo permission errors — which explains why this keeps getting reported. Anyone following official npm docs will hit this.
See also #7231 (same bug, Linux, closed as not planned).
Same issue here. macOS, Claude Code v2.1.37, native installation via
curl | bash.~/.npmrchasprefix=/Users/dannywannagat/.local, which causes the false positive:Confirmed:
npm list -g @anthropic-ai/claude-codereturns nothing. The binary is a symlink to the native installation:As @dave-shawley identified, the detection logic checks where npm would install, not whether an npm package actually exists. A simple
npm list -gcheck before flagging would fix this.Still hitting this on macOS (Darwin 25.1.0, Apple Silicon) with v2.1.38 native installation.
In my case it's not just a false warning — the config actively reverts. I've manually fixed this multiple times across sessions by:
~/.claude.jsonto setinstallMethod: "native"andautoUpdates: truenpm -g uninstall @anthropic-ai/claude-codeEach time, within some period of normal use, the config silently resets back to
installMethod: "global"andautoUpdates: false, and the npm package reappears at/opt/homebrew/bin/claude. Auto-updates stay broken until I manually intervene again.autoUpdatesProtectedForNative: trueis present in my config but does not prevent the reset.claude doctoroutput after it happens:This matches the root cause identified in #17612 — the auto-updater appears to unconditionally write
installMethod: "global"and then the npm-global installation follows from that.Workaround (PATH priority): In addition to the config fix, I found that on macOS,
~/.local/bin(where native claude lives) was ending up behind/opt/homebrew/binin PATH due to macOSpath_helperreordering. This means even after removing the npm package, the auto-updater could reinstall via npm and that binary would take priority. Fix: addexport PATH="$HOME/.local/bin:$PATH"as the last line in~/.zprofile(afterbrew shellenv), not just in.zshrc, sincepath_helperreorders PATH in login shells. This ensures the native binary always wins.Still happening on v2.1.39 (native installation, macOS Darwin 25.2.0, Apple Silicon). Discovered this running
claude update— the warning also appears there, not just inclaude doctor.As @oskay described, the detection logic misidentifies Homebrew cask installations at
/opt/homebrew/bin/claudeasnpm-globaland suggestsnpm -g uninstall @anthropic-ai/claude-code— which does nothing since there's no npm package installed.The correct fix for Homebrew users is:
---
Root cause analysis from decompiling v2.1.39 binary
The detection logic in
findInstallations()(minified asXE8) works like this:npm -g config get prefixto get npm's global prefix path{prefix}/bin/claudeexists (e.g./opt/homebrew/bin/claude)realpathSync()and checks if the resolved path includes/Caskroom/isHomebrewInstallation()(minified asUVR) — but this function checksprocess.execPath, not the path being evaluatedThe bug: When running the native binary at
~/.local/bin/claude,process.execPathis~/.local/share/claude/versions/X.Y.Z— it doesn't contain/Caskroom/. SoisHomebrewInstallation()returnsfalse, and the Homebrew binary at/opt/homebrew/bin/claudefalls through totype: "npm-global".The symlink resolution already proved it's Homebrew (
realpathSync("/opt/homebrew/bin/claude").includes("/Caskroom/")wastrue), but the result is discarded.Then in the doctor/update diagnostics, the fix message is hardcoded for
npm-global:Suggested fix
findInstallations(): WhenrealpathSync(path).includes("/Caskroom/")is alreadytrue, classify as{ type: "homebrew", path }directly — don't delegate toisHomebrewInstallation()which checks the wrong binary.type: "homebrew"separately:Note: the CHANGELOG for v2.0.33 states "Fixed
claude doctorincorrectly detecting Homebrew vs npm-global installations by properly resolving symlinks" — the symlink resolution was added but the result isn't used correctly becauseisHomebrewInstallation()checksprocess.execPath(the running binary) instead of the path that was just resolved.Some people actually want to manage the software on their system via a central package manager like Homebrew or MacPorts. (I happen to be the maintainer of the
claude-codeport for MacPorts.) In that case, telling the user to uninstall the software via their package manager is not appropriate advice.I think that ideally there should be a generic way for package managers to let the
claudebinary know that it is being managed by a package manager, e.g. an environment variable or something.Looking at the existing settings, I would expect that settings
DISABLE_INSTALLATION_CHECKS=1would suppress the installation checks, but that doesn't seem to be the case:There are two issues in this output:
~/.local/binto their PATH, but that directory doesn't even exist on my system, so that's bad advice./opt/local/bin/claudeis a 'leftover npm global installation', but it is not./opt/local/bin/claudeis a wrapper script that calls/opt/local/share/claude-code/claude, which is the single-fileclaudebinary, not an NPM installation, so this remark is also incorrect. (npm config get prefixreturns/opt/localfor MacPorts users, or whatever directory they specified if they use a custom prefix for their MacPorts setup.)Same issue here on Ubuntu Linux with Claude Code 2.1.70. Native installation via
curl | bash, Linux x86_64. npm prefix is~/.local(set in~/.npmrcper npm's own recommendation).The detection should verify that the npm package actually exists before flagging a path as
npm-global— for example, check whether{prefix}/lib/node_modules/@anthropic-ai/claude-codeexists. This is the standard location for globally-installed npm packages and would distinguish a real npm installation from a native binary that happens to share the same directory. Alternatively, deduplicating entries that resolve to the same file via symlink would also work.I’m seeing a very similar problem on Windows (native install), with timestamped evidence that npm global install is being triggered again.
What happens
Even after removing npm global installation and using native install,
installMethodflips fromnativetoglobal, and npm artifacts are recreated.Timestamped evidence (JST)
installMethodchangednative → global(autoUpdates=false)verbose title npm install @anthropic-ai/claude-codeverbose argv "install" "--global" "@anthropic-ai/claude-code"Additional context
autoUpdates=falseclaude install,claude update, ornpm -g install(normal usage flow included/doctor).<details>
<summary>Redacted analysis report</summary>
</details>
<details>
<summary>Redacted npm debug log snippet</summary>
</details>
If helpful, I can also share a longer redacted timeline from the monitor run.
The issue still exists as of v2.1.92
Still reproducing on v2.1.119 (Linux x86_64, Ubuntu 24.04.4, native install via
curl | bash).Same scenario as @pogo19 and @danwan: npm prefix happens to be
~/.local, which is also where the native installer places the symlink. The path~/.local/bin/claudeis a symlink →~/.local/share/claude/versions/2.1.119, andnpm ls -gconfirms no@anthropic-ai/claude-codepackage exists.Warning appears in both
claude doctorandclaude update. The suggested fixnpm -g uninstall @anthropic-ai/claude-codeis a no-op (nothing to uninstall).@danwan's suggestion — running
npm list -g @anthropic-ai/claude-code(or equivalently checking{prefix}/lib/node_modules/@anthropic-ai/claude-code) before flagging the path asnpm-global— would resolve this without requiring users to move their npm prefix away from the officially-recommended~/.local.I hate having to write a comment that brings nothing new to the conversation and spamming the inboxes of 15 people, but since this is apparently the expected etiquette in this repository, and the issues in which this doesn't happen get closed automatically "due to inactivity", here we go:
I'm also facing this bogus "multiple installations found" warning, for example, when running
claude update:Both installations point at the same path, Claude Code has never been installed using npm on this VM, and the suggested "fix" is of course a no-op.
My
$NPM_CONFIG_PREFIXis set to~/.localwhich is a normal and expected thing to do.