Skip to content

fix(arborist): forward transitive overrides through linked store links#9658

Merged
owlstronaut merged 1 commit into
npm:latestfrom
manzoorwanijk:fix/linked-transitive-override-invalid-ls
Jun 25, 2026
Merged

fix(arborist): forward transitive overrides through linked store links#9658
owlstronaut merged 1 commit into
npm:latestfrom
manzoorwanijk:fix/linked-transitive-override-invalid-ls

Conversation

@manzoorwanijk

Copy link
Copy Markdown
Contributor

In continuation of our exploration of using install-strategy=linked in the Gutenberg monorepo, which powers the WordPress Block Editor.

Under install-strategy=linked, an override that forces a transitive dependency to a version outside its dependent's declared range was applied on disk but reported as invalid by npm ls --all, which then exited 1 (ELSPROBLEMS). The hoisted strategy reports the same edge as overridden and exits 0. The bug only surfaced when the overridden package's dependent was itself a transitive (store) package — a direct dependency of the root was handled correctly.

npm ls rebuilds the actual tree from the .store layout, and an OverrideSet propagates down the tree through Link.recalculateOutEdgesOverrides, which forwards the set from a store symlink to its target node. A prior fix (#9357) gated that forwarding on a rule naming a direct dependency of the target, to avoid flipping an unrelated target to "has overrides" and making npm ci re-resolve lockfile-pinned edges. That gate was too narrow: a store link whose own direct deps do not name the overridden package never forwarded the set, so the chain to the deeper dependent → overridden edge never received the rule and was reported invalid.

The fix walks the target's subtree (following resolved edges, dereferencing links) and forwards the set when an override rule actually applies to any reachable edge, matched via getEdgeRule on name and spec so a non-applicable version-qualified rule still does not flip an intermediate node. Because override propagation is event-driven during load, a store link can run its check before its subtree is resolved; loadActual therefore re-forwards through links once the tree is complete, so the filesystem-scan path resolves transitive overrides as overridden rather than invalid.

References

Fixes #9619

@manzoorwanijk manzoorwanijk marked this pull request as ready for review June 25, 2026 11:36
@manzoorwanijk manzoorwanijk requested review from a team as code owners June 25, 2026 11:36
@owlstronaut owlstronaut merged commit 541c286 into npm:latest Jun 25, 2026
24 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Backport to release/v11 failed.

This usually means the cherry-pick had conflicts. Please create a manual backport:

git fetch origin release/v11
git checkout -b backport/v11/9658 origin/release/v11
git cherry-pick -x 541c2865bf2a961554c889f5764bf182cc7f60e2
# resolve any conflicts, then:
git push origin backport/v11/9658
Error details
Command failed: git cherry-pick -x 541c2865bf2a961554c889f5764bf182cc7f60e2
error: could not apply 541c2865b... fix(arborist): forward transitive overrides through linked store links (#9658)
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
hint: Disable this message with "git config set advice.mergeConflict false"

@manzoorwanijk manzoorwanijk deleted the fix/linked-transitive-override-invalid-ls branch June 25, 2026 18:22
@owlstronaut

Copy link
Copy Markdown
Contributor

@manzoorwanijk this'll need a backport

@manzoorwanijk

Copy link
Copy Markdown
Contributor Author

Already on it...

@manzoorwanijk

Copy link
Copy Markdown
Contributor Author

Here you go #9668

owlstronaut pushed a commit that referenced this pull request Jun 25, 2026
#9658) (backport release/v11) (#9668)

Backport of #9658 to `release/v11`.

Under `install-strategy=linked`, an override forcing a transitive
dependency outside its dependent's declared range was applied on disk
but reported as `invalid` by `npm ls --all`, which then exited 1
(`ELSPROBLEMS`); hoisted reports it as `overridden` and exits 0. It only
surfaced when the overridden package's dependent was itself a transitive
(store) package.

`Link.recalculateOutEdgesOverrides` only forwarded an OverrideSet to a
store link's target when a rule named a direct dependency of the target,
so the chain to a deeper `dependent -> overridden` edge never received
the rule. The fix walks the target's subtree and forwards when a rule
actually applies to a reachable edge (matched via `getEdgeRule` on name
and spec, preserving #9357), and `loadActual` re-forwards through
links once the tree is complete.

Cherry-picked cleanly except for a context-only conflict in
`load-actual.js` and its test file: the unrelated `packageExtensions`
and `.npm-extension` methods and the `applies root packageExtensions to
a linked actual tree` test are not present on `release/v11`, so they
were dropped from the resolution. Only this fix's changes are included.

## References

Backports #9658
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] install-strategy=linked: an applied override is reported invalid by npm ls (exit 1)

2 participants