-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Current Behavior
If you:
- have multiple versions of transitive optional dependencies in a workspace (e.g. vite -> esbuild -> @esbuild/darwin-arm64, and vitest -> vite -> esbuild -> @esbuild/darwin-arm64)
- have dependency in the root package that also has those transitive optional dependencies via a peer dependency
Then:
- running
npm install
will prune the unhoisted versions, and possibly fail. esbuild in particular uses a postinstall script to do introspection of its expected optional dependencies, and it will blow up if they are missing/wrong
Expected Behavior
Running npm install
should not prune transitive optional dependencies. This works correctly on npm 11.4.2 and below.
Steps To Reproduce
- Clone https://github.com/jenseng/npm-install-loses-transitive-peer-deps
- Run
npm install
- See an error like:
npm error code 1
npm error path /path/to/npm-install-loses-transitive-peer-deps/node_modules/vitest/node_modules/esbuild
npm error command failed
npm error command sh -c node install.js
npm error /path/to/npm-install-loses-transitive-peer-deps/node_modules/vitest/node_modules/esbuild/install.js:133
npm error throw new Error(`Expected ${JSON.stringify(versionFromPackageJSON)} but got ${JSON.stringify(stdout)}`);
npm error ^
npm error
npm error Error: Expected "0.21.5" but got "0.18.20"
npm error at validateBinaryVersion (/path/to/npm-install-loses-transitive-peer-deps/node_modules/vitest/node_modules/esbuild/install.js:133:11)
npm error at /path/to/npm-install-loses-transitive-peer-deps/node_modules/vitest/node_modules/esbuild/install.js:283:5
npm error
npm error Node.js v22.18.0
This is because esbuild's postinstall script does some sanity checks to ensure its platform-specific optional dependency is there. Because of the bug, 0.21.5 is not installed, so it finds the hoisted version and throws the error.
Alternative repro:
- Run
npm install --ignore-scripts
- While it will "succeed", note that package-lock.json has now lost the unhoisted versions of all those optional dependencies, and they are not installed
Additional notes:
I tried to distill this down to a simpler repro, perhaps it could be taken further. There do seem to be at least a few conditions to trigger the bug:
- You have to be using workspaces
- The workspaces need to have two different versions of some transitive optional dependencies
- The root package needs a dependency, that has a peer dependency, that also has the transitive optional dependencies (unclear if the version matters)
I've confirmed the bug is present in npm 11.5.0 onward, and is not present in npm 11.4.2 or earlier. So perhaps this PR is the culprit.
In my repro repo, the root package dependency uses a file URL to point at a tarball in the same repo, but the bug also happens for packages fetched from the registry (that's where I first encountered it)
Environment
- npm: 11.5.2
- Node.js: 22.18.0
- OS Name: Mac OS Sequoia 15.6
- System Model Name: Macbook Pro
- npm config:
; copy and paste output from `npm config ls` here