-
Notifications
You must be signed in to change notification settings - Fork 4.3k
[BUG] Overrides with shared transitive deps cause silent exit 1 #9109
Description
Found while testing overrides in WordPress/gutenberg. We're switching to strict-peer-deps after adopting linked strategy and wanted to test react/react-dom overrides ahead of time. npm install just exits with code 1 and no error message.
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
Adding two or more packages to overrides that share a transitive dep (e.g. react + react-dom both pull in loose-envify) causes npm install to silently exit 1 in large monorepos. No error, no ERESOLVE, nothing — just exit code 1 and a log file pointer.
Expected Behavior
Install should succeed, or show a clear error message.
Steps To Reproduce
mkdir -p repro/packages/{app,editor}
cd repro
cat > package.json << 'EOF'
{
"name": "override-repro",
"private": true,
"workspaces": ["packages/*"],
"devDependencies": {
"react": "18.3.1",
"react-dom": "18.3.1"
},
"overrides": {
"react": "$react",
"react-dom": "$react-dom"
}
}
EOF
for pkg in app editor; do
cat > "packages/$pkg/package.json" << PKGEOF
{
"name": "@repro/$pkg",
"private": true,
"dependencies": { "react": "18.3.1", "react-dom": "18.3.1" }
}
PKGEOF
done
echo 'install-strategy=linked' > .npmrc
npm install --loglevel=silly 2>&1 | grep -i conflicting
# silly Conflicting override sets <OverrideSet react> <OverrideSet react-dom>
# silly Conflicting override sets loose-envifyIn this minimal repro the install finishes (exit 0) because the tree is small. In Gutenberg (hundreds of workspaces), the broken state cascades into an ERESOLVE during buildDeps, and then the error formatting crashes — so you get a silent exit 1.
Root Cause
Two bugs combine:
1. Sibling override sets treated as conflicting
findSpecificOverrideSet in override-set.js walks parent chains to see if one override set contains the other. Sibling sets (e.g. the react and react-dom children of the root override set) are never ancestors of each other, so it returns undefined. This leaves shared deps like loose-envify with an inconsistent override state. The existing haveConflictingRules check (which handles this correctly) is not used in this path.
2. ERESOLVE report crashes with depth=Infinity
explain-eresolve.js generates the full report file with depth=Infinity. In large monorepos (especially linked strategy), this recurses through the entire dep graph and eventually hits RangeError: Invalid string length. That error is thrown inside the error formatter, which swallows the original ERESOLVE — so you get exit 1 with no message at all.
Workaround
legacy-peer-deps = true in .npmrc.
Environment
- npm: 11.11.1
- Node.js: 22.20.0
- OS Name: macOS
- npm config:
install-strategy=linked,strict-peer-deps=true