anthropics / anthropics/claude-code

[BUG] WSL: package-manager installs are classified "native" — ownsExecutable returns before it can run dpkg -S / rpm -qf

Open
#95,575 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:packaging bug has repro platform:wsl
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
  1. On WSL2, install via the apt repo (https://downloads.claude.ai/claude-code/apt/stable).
  2. Confirm the package manager owns the binary:
$ dpkg -S /usr/bin/claude
claude-code: /usr/bin/claude
  1. 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.