Skip to content

[BUG] npm exec -w a -w b -- <bin> runs the first workspace's bin for every workspace #9640

Description

@manzoorwanijk

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 npm exec targets more than one workspace and the requested command resolves to a different workspace-local bin in each (same bin name, different package), every workspace runs the first workspace's bin instead of its own.

This is not specific to the linked install strategy — it reproduces identically under the default hoisted strategy.

The cause is module-level state in libnpmexec: binPaths is declared once at module scope (workspaces/libnpmexec/lib/index.js) and pushed to on each invocation, but never reset. npm exec --workspace runs callExec once per workspace in the same process, so the bin directory found for the first workspace stays at the front of the resolved bin list for every subsequent workspace, shadowing each workspace's own bin of the same name.

Expected Behavior

Each workspace targeted by npm exec should resolve and run its own local bin. Running npm exec -w a -w b -- shared-bin should execute a's shared-bin in a and b's shared-bin in b.

Steps To Reproduce

cd "$(mktemp -d)"
echo '{ "name": "root", "version": "1.0.0", "workspaces": ["packages/*"] }' > package.json
mkdir -p packages/a packages/b packages/tool-a packages/tool-b
echo '{ "name": "a", "version": "1.0.0", "dependencies": { "tool-a": "*" } }' > packages/a/package.json
echo '{ "name": "b", "version": "1.0.0", "dependencies": { "tool-b": "*" } }' > packages/b/package.json
echo '{ "name": "tool-a", "version": "1.0.0", "bin": { "shared-bin": "cli.js" } }' > packages/tool-a/package.json
echo '{ "name": "tool-b", "version": "1.0.0", "bin": { "shared-bin": "cli.js" } }' > packages/tool-b/package.json
printf '#!/usr/bin/env node\nconsole.log("A bin")\n' > packages/tool-a/cli.js
printf '#!/usr/bin/env node\nconsole.log("B bin")\n' > packages/tool-b/cli.js
chmod +x packages/tool-a/cli.js packages/tool-b/cli.js
npm install

npm exec -w a -w b -- shared-bin
#   actual:    "A bin" / "A bin"
#   expected:  "A bin" / "B bin"

Environment

  • npm: 12.0.0-pre.1
  • Node.js: 24.17.0
  • OS Name: macOS 26.5.1
  • System Model Name: MacBook Pro (Apple Silicon)
  • npm config:
; copy and paste output from `npm config ls` here

Notes

Distinct from the linked-only #9616 (workspace-local bin ignored under linked). This bug affects all install strategies and only surfaces when a single npm exec spans multiple workspaces that each provide a same-named bin.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions