anthropics / anthropics/claude-code
[BUG] WSL: package-manager installs are classified "native" — ownsExecutable returns before it can run dpkg -S / rpm -qf
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 147k
- Forks
- 24k
- PR merge metrics
- PR metrics pending
Description
Summary
On WSL, an install owned by the system package manager is classified as native, so the bundled self-updater takes over a binary the package manager owns. claude doctor reports Running: native for an apt install, and omits the Package manager: line it emits on non-WSL Linux.
Same shape as #89097: a platform-string branch that treats wsl and linux as disjoint where the Linux path is correct on WSL.
Root cause
In 2.1.267, every distro-package detector routes through ownsExecutable, which returns before it runs the ownership command (line breaks added, otherwise verbatim):
detectPacman(){return this.pacman??=this.ownsExecutable(["arch"],"pacman",["-Qo"])}
detectDeb(){return this.deb??=this.ownsExecutable(["debian"],"dpkg",["-S"])}
detectRpm(){return this.rpm??=this.ownsExecutable(["fedora","rhel","suse"],"rpm",["-qf"])}
detectApk(){return this.apk??=this.ownsExecutable(["alpine"],"apk",["info","--who-owns"])}
async ownsExecutable(e,n,i){
if(this.sources.platform()!=="linux")return!1;
let r=await this.getOsRelease();
if(r&&!Z(r,e))return!1;
let s=await this.sources.execFileNoThrow(n,[...i,this.sources.execPath()],{timeout:5000,useCwd:!1,useToolMemoryCgroup:!1});
if(s.code===0&&s.stdout)return t(`Detected ${n} installation: ${s.stdout.trim()}`),!0;
return!1
}
getPlatform() never yields linux under WSL:
else if(this.sources.platform==="linux")
if(this.sources.env.WSL_DISTRO_NAME||this.sources.env.WSL_INTEROP)this.platform="wsl";
else{let e=this.kernelString();this.platform=e!==void 0&&Nen(e)?"wsl":"linux"}
so all four detectors return false without executing, and the resolver falls through:
if(wht()||_()||F()||G()||await E()||await j()||await H()||await U())return"package-manager";
return"native"
detectHomebrew in the same class does accept WSL, so a Homebrew install on WSL is classified correctly while a dpkg-owned one is not:
detectHomebrew(){let e=this.sources.platform();if(e!=="macos"&&e!=="linux"&&e!=="wsl")return!1;
Steps to reproduce
- On WSL2, install via the apt repo (
https://downloads.claude.ai/claude-code/apt/stable). - Confirm the package manager owns the binary:
$ dpkg -S /usr/bin/claude
claude-code: /usr/bin/claude
- Run
claude doctor:
Running: native (2.1.267)
Commit: a9e1808c8204
Platform: linux-x64
Path: /usr/bin/claude
Config install method: unknown
Search: OK (bundled)
Auto-updates: disabled (set by env: DISABLE_AUTOUPDATER)
Auto-update channel: latest
Last update attempt: none recorded
Running: native, and no Package manager: line — that field is only populated when the type resolves to package-manager. No native installation exists on the machine to account for it: ~/.local/bin/claude, ~/.local/share/claude, ~/.claude/local and ~/.claude/versions are all absent, and the Path above is the dpkg-owned binary from step 2. (DISABLE_AUTOUPDATER is set here as a local workaround for this bug and has no bearing on the classification.)
Contrast #87197, the same apt install on non-WSL Linux, where detection works: Running: package-manager, Package manager: deb, Auto-updates: Managed by package manager.
Expected behavior
On WSL, a dpkg/rpm/pacman/apk-owned install resolves to package-manager and the self-updater defers to the package manager, the same as on non-WSL Linux.
Suggested fix
Let ownsExecutable accept wsl alongside linux. The collapse already exists in the codebase:
function Wle(){let e=M(),n=e==="wsl"&&!Kc()?"linux":e;
function Hn(e){return e==="wsl"?["wsl","linux"]:[e]}
and the tool-memory cgroup path already tests both:
function Kn(e){let n=M();if(n!=="linux"&&n!=="wsl")return;
Environment
- Claude Code 2.1.267 (
a9e1808c8204), installed from the apt repo at/usr/bin/claude - WSL2, Debian 13 (
ID=debian), linux-x64 - Anthropic API
Symbol names are from the minified 2.1.267 bundle and will differ between builds.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Locate the package-manager detection entry points ownsExecutable and getPlatform, then run the WSL reproduction with dpkg -S /usr/bin/claude and claude doctor. Verify that distro detectors execute on WSL and that a dpkg/rpm/pacman/apk-owned install resolves to package-manager, reports the package manager, and does not use native updating.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100