Skip to content

[BUG] Overrides with shared transitive deps cause silent exit 1 #9109

@manzoorwanijk

Description

@manzoorwanijk

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-envify

In 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions