npm / npm/cli

[BUG] Workspace Bin Hoisting Collision causes incorrect binary execution via npm exec

Open
#9,712 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Needs Triage
Dominant language
JavaScript
Stars
10.1k
Forks
4.7k
Avg merge
2d 2h
Merged PRs (30d)
19

Description

Is there an existing issue for this?
  • I have searched the existing issues
This issue exists in the latest npm version
  • I am using the latest npm
This is not just a request to bump a dependency for a CVE
  • This is not solely a request to bump a dependency for a CVE
Current Behavior

When two workspaces each depend on a different package that exports a binary with the exact same name, Arborist hoists both dependencies to the root node_modules/. However, because bin-links uses a "first-wins" mechanism, only one shim gets created in root/node_modules/.bin/.

As a result, when running npm exec -w <loser-workspace> -- <bin>, libnpmexec falls back to the root .bin folder and inadvertently executes the wrong binary (the one belonging to the other workspace's dependency) because a local .bin folder was never created for the workspace.

Expected Behavior

npm exec -w <workspace> should completely isolate identical binary names in a monorepo and always execute the binary that belongs to the target workspace's dependency tree, regardless of hoisting rules at the root.

Steps To Reproduce
  1. Create a monorepo with two workspaces: workspace-a and workspace-b.
  2. Install dep-1 (which exports a bin named my-cli) into workspace-a.
  3. Install dep-2 (which also exports a bin named my-cli) into workspace-b.
  4. Observe that both dependencies hoist to the root. Only one of them (e.g., dep-1) gets its my-cli shim created in root/node_modules/.bin/.
  5. Run npm exec -w workspace-b -- my-cli (the one that "lost" the race).
  6. See that dep-1's script is executed instead of dep-2's script.
Environment
  • npm: 12.0.0-pre.2
  • Node.js: v23.11.1
  • OS Name: macOS 15.7.7
  • System Model Name: MacBookPro18,1
  • npm config:
; "user" config from /Users/arjun/.npmrc

//registry.npmjs.org/:_authToken = (protected)

; "project" config from /Users/arjun/Desktop/npm/.npmrc

package-lock = true

; node bin location = /Users/arjun/.nvm/versions/node/v23.11.1/bin/node
; node version = v23.11.1
; npm local prefix = /Users/arjun/Desktop/npm
; npm version = 12.0.0-pre.2
; cwd = /Users/arjun/Desktop/npm
; HOME = /Users/arjun
; Run `npm config ls -l` to show all defaults.

Contributor guide

Open the contributing guide

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

Start by reproducing the workspace setup described in the issue and inspect how bin-links creates root and workspace .bin shims. Trace the npm exec workspace path through libnpmexec, especially its fallback to the root .bin folder. Done means npm exec -w workspace-b -- my-cli runs dep-2's binary when dep-1 and dep-2 export the same name.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nodejs
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.