fix(arborist): resolve sibling override sets via common ancestor#9110
Conversation
Sibling override sets (e.g. react + react-dom children of root) were treated as conflicting because findSpecificOverrideSet only checked ancestor relationships. Now checks haveConflictingRules and falls back to the nearest common ancestor when rules are compatible. Also caps ERESOLVE report depth to 16 and adds cycle detection in explain-dep to prevent RangeError: Invalid string length in large trees.
4166f55 to
9e08077
Compare
|
|
||
| return { | ||
| explanation: `${explain(expl, chalk, 4)}\n\n${fix}`, | ||
| file: `# npm resolution error report\n\n${explain(expl, noColorChalk, Infinity)}\n\n${fix}`, |
There was a problem hiding this comment.
This is done on purpose so that the eresolve-report.txt has the full json output. See the comment on line 6.
There was a problem hiding this comment.
You're right, reverted that change. The depth=Infinity is preserved.
The underlying issue was that in large linked-strategy trees, cycles in the dependency graph (e.g. store nodes referencing each other) caused explainFrom to recurse infinitely, eventually hitting RangeError: Invalid string length.
The fix is now in explain-dep.js instead - added stack-based cycle detection in explainFrom so it breaks out of recursive cycles while still fully expanding diamond dependencies (same node reached via different paths). This way, the full report is still generated as intended, just without infinite recursion.
Two bugs combine to cause
npm installto silently exit 1 in large monorepos when multiple packages are listed inoverridesand share a transitive dependency.Bug 1 — Sibling override sets treated as conflicting:
findSpecificOverrideSetwalks parent chains to determine if one override set contains the other. Sibling sets (e.g. thereactandreact-domchildren of the root override set) are never ancestors of each other, so it returnedundefined. This left shared transitive deps likeloose-envifywith an inconsistent override state, eventually causing an ERESOLVE duringbuildDeps. Fixed by checkinghaveConflictingRules(which already existed but was not used in this path) and falling back to the nearest common ancestor when the rules are compatible.Bug 2 — ERESOLVE report crashes with infinite depth:
explain-eresolve.jsgenerates the full report file withdepth=Infinity. In large trees (especially linked strategy), cycles in the dependency graph (e.g. store nodes referencing each other) causeexplainFromto recurse infinitely, hittingRangeError: Invalid string length. That error is thrown inside the error formatter, which swallows the original ERESOLVE — so you get exit 1 with no message. Fixed by adding cycle detection inexplain-dep.jsusing stack-basedseentracking (add on enter, delete on leave) so diamond dependencies still work but cycles are broken.Also capped report depth to 16.(reverted —depth=Infinityis intentional for the full report file)Found while testing overrides in WordPress/gutenberg#75814.
References
Fixes #9109