-
Notifications
You must be signed in to change notification settings - Fork 4.3k
[BUG] Overrides ignored for transitive dependencies with install-strategy=linked #9197
Description
Found while testing overrides in WordPress/gutenberg. We're switching to strict-peer-deps after adopting the linked strategy.
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
Somewhat related to #9109
When using install-strategy=linked, npm overrides for transitive dependencies are ignored. The overridden version is installed but the parent's edge still expects the lockfile version, marking the overridden package as invalid. With strict-peer-deps=true, this causes an ERESOLVE error and the install fails completely.
With the default hoisted strategy, the same overrides work correctly — the overridden packages are installed and marked as overridden in the tree.
Expected Behavior
Overrides should work the same way regardless of install strategy. The overridden version should satisfy the parent's dependency edge, just like it does with hoisted.
Steps To Reproduce
Setup (common to both strategies)
rm -rf /tmp/npm-override-bug
mkdir -p /tmp/npm-override-bug
cd /tmp/npm-override-bug
cat > package.json << 'EOF'
{
"name": "override-bug-repro",
"version": "1.0.0",
"private": true,
"devDependencies": {
"typescript": "5.8.3",
"@typescript-eslint/utils": "8.51.0"
}
}
EOFWith linked strategy (BUG)
echo 'install-strategy=linked' > .npmrc
# 1. Install to create lockfile with 8.51.0 versions
npm install
# 2. Upgrade to TS 6 and add overrides for transitive deps
cat > package.json << 'EOF'
{
"name": "override-bug-repro",
"version": "1.0.0",
"private": true,
"devDependencies": {
"typescript": "6.0.2",
"@typescript-eslint/utils": "8.51.0"
},
"overrides": {
"@typescript-eslint/typescript-estree": "8.58.0",
"@typescript-eslint/project-service": "8.58.0"
}
}
EOF
# 3. Reinstall — override is applied but tree is invalid
npm install
npm ls @typescript-eslint/typescript-estree
# Actual: @typescript-eslint/typescript-estree@8.58.0 invalid: "8.51.0"
# Expected: @typescript-eslint/typescript-estree@8.58.0 overriddenWith hoisted strategy (WORKS)
rm -rf /tmp/npm-override-bug
mkdir -p /tmp/npm-override-bug
cd /tmp/npm-override-bug
# ... same setup as above, without the .npmrc ...
npm install
# ... same package.json change as above ...
npm install
npm ls @typescript-eslint/typescript-estree
# @typescript-eslint/typescript-estree@8.58.0 overridden ✓With strict-peer-deps=true
Adding strict-peer-deps=true to the .npmrc makes it worse — step 3 fails outright with ERESOLVE, and the override is completely ignored:
npm error ERESOLVE could not resolve
npm error While resolving: @typescript-eslint/project-service@8.51.0
npm error Found: typescript@6.0.2
npm error Could not resolve dependency:
npm error peer typescript@">=4.8.4 <6.0.0" from @typescript-eslint/project-service@8.51.0
Cleanup
rm -rf /tmp/npm-override-bugRoot Cause Analysis
During loadVirtual in load-virtual.js, nodes loaded from the lockfile are created without override context. When the linked strategy builds the tree, override propagation through parent edges doesn't properly update the edge's expected spec, so the overridden version is treated as invalid rather than overridden.
In hoisted mode, when an invalid edge is detected after loading the virtual tree, it gets queued for re-resolution in #initTree (build-ideal-tree.js ~line 340). The linked strategy appears to handle these differently, skipping re-resolution for overridden transitive deps.
Environment
- npm: v11.12.1 (fork, latest branch)
- Node.js: v24.14.0
- OS: macOS (Darwin 25.4.0)
- npm config:
install-strategy=linked strict-peer-deps=true ; (optional, makes it worse)