Visitar URL original
fix(arborist): keep an optional peer that shadows a version not satisfying it by HardMax71 · Pull Request #10087 · npm/cli · GitHub
Skip to content

fix(arborist): keep an optional peer that shadows a version not satisfying it - #10087

Open
HardMax71 wants to merge 1 commit into
npm:latestfrom
HardMax71:fix/keep-shadowing-optional-peer
Open

HardMax71 wants to merge 1 commit into
npm:latestfrom
HardMax71:fix/keep-shadowing-optional-peer

Conversation

@HardMax71

Copy link
Copy Markdown

Fixes #10086. Related to #9249 (same prune of extraneous optional peers, different outcome).

calcDepFlags leaves a node extraneous when it is only reachable through a peerOptional edge, so #idealTreePrune removes it after a lockfile-based install that changed the tree. That is fine when the edge just ends up missing. But when the pruned copy was nested to avoid a conflict, the edge falls through to a node further up that does not satisfy it, and the saved lockfile has an invalid edge (npm ls fails with ELSPROBLEMS, npm 10 npm ci refuses the lockfile).

Now such a node is no longer marked extraneous when the node it shadows (the same name resolved from above its parent) exists and does not satisfy the edge. An optional peer that only fills an empty slot, or shadows a version that also satisfies the edge, is still pruned as before.

Tests: a unit test in test/calc-dep-flags.js covers both cases and fails without the change. The nest when peerOptional conflicts snapshot in build-ideal-tree loses one "extraneous": true line: that test builds exactly this layout, and the nested optional peer it asserts on was flagged for removal on the next install.

End to end with the repro from the issue: after npm install --save-exact jsdom@30.0.1 the lockfile keeps the nested @noble/hashes@2.3.0 copies, npm ls reports nothing invalid, and both this branch's npm ci and npm 10 npm ci accept it. The arborist suite passes with 100% coverage, and so do the install, ci and ls command tests.

…fying it

An optional peer that is only reachable through its peerOptional edge is
pruned as extraneous. When it was nested to avoid a conflict, pruning it
leaves the edge resolving to a node further up that does not satisfy it.
@HardMax71
HardMax71 requested a review from a team as a code owner October 6, 2026 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] npm install <pkg> on an existing lockfile prunes a nested optional peer and leaves its edge invalid

2 participants