Is there an existing issue for this?
This issue exists in the latest npm version
This is not just a request to bump a dependency for a CVE
Current Behavior
Under install-strategy=linked, a root packageExtensions rule adds the missing edge, the install succeeds, and the lockfile records it with packageExtensionsApplied. But every command that reads the actual installed tree loses that edge:
npm ls --all --json omits the extension-created dependency and its provenance.
npm explain <dep> → No dependencies found matching <dep>.
npm patch add <dep> → EPATCHNOTINSTALLED.
Hoisted is unaffected, and normally-declared transitive deps under linked are unaffected — only edges that exist solely because of packageExtensions.
Expected Behavior
npm ls, npm explain, and npm patch add should agree with the lockfile and runtime layout under linked, as they do under hoisted.
Steps To Reproduce
broken-runtime requires missing-runtime at runtime but doesn't declare it; packageExtensions adds the edge. Use any registry serving both packages (e.g. a local one).
mkdir app && cd app
cat > .npmrc <<'EOF'
install-strategy=linked
EOF
cat > package.json <<'EOF'
{
"name": "repro",
"version": "1.0.0",
"dependencies": { "broken-runtime": "1.0.0" },
"packageExtensions": {
"broken-runtime@1": { "dependencies": { "missing-runtime": "^1.0.0" } }
}
}
EOF
npm install --ignore-scripts
node -e "require('broken-runtime')()" # works at runtime
npm ls --all --json # omits missing-runtime + packageExtensionsApplied
npm explain missing-runtime # npm error No dependencies found matching missing-runtime
npm patch add missing-runtime # npm error code EPATCHNOTINSTALLED
# Control: drop install-strategy=linked, reinstall -> all three succeed.
Environment
- npm: 12.0.0-pre.0
- Node.js: v24.15.0
- OS: Darwin 25.5.0 (macOS, arm64)
- Config:
install-strategy=linked, root packageExtensions
Is there an existing issue for this?
This issue exists in the latest npm version
This is not just a request to bump a dependency for a CVE
Current Behavior
Under
install-strategy=linked, a rootpackageExtensionsrule adds the missing edge, the install succeeds, and the lockfile records it withpackageExtensionsApplied. But every command that reads the actual installed tree loses that edge:npm ls --all --jsonomits the extension-created dependency and its provenance.npm explain <dep>→No dependencies found matching <dep>.npm patch add <dep>→EPATCHNOTINSTALLED.Hoisted is unaffected, and normally-declared transitive deps under linked are unaffected — only edges that exist solely because of
packageExtensions.Expected Behavior
npm ls,npm explain, andnpm patch addshould agree with the lockfile and runtime layout under linked, as they do under hoisted.Steps To Reproduce
broken-runtimerequiresmissing-runtimeat runtime but doesn't declare it;packageExtensionsadds the edge. Use any registry serving both packages (e.g. a local one).Environment
install-strategy=linked, rootpackageExtensions