You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG] install-strategy=linked re-creates a removed workspace's directory on npm install #9331
While trying to fix #5463 via #9330 I found this issue
Current Behavior
When a workspace's directory has been deleted from disk and the entry has been removed from the root package.json's workspaces array, running npm install --install-strategy=linked re-creates the deleted workspace directory as an empty shell containing a self-referential symlink:
packages/b/
└── node_modules/
└── b -> ..
No source files (no package.json, no index.js) are restored — just the directory and a <workspace>/node_modules/<name> -> .. symlink loop. The symlink target (..) points at the empty packages/b/ directory itself, so resolving it leads back to the same empty shell.
The hoisted (default) strategy does not exhibit this — the deleted directory stays deleted.
Expected Behavior
A workspace removed from package.json's workspaces array and deleted from disk should remain absent after npm install, regardless of install-strategy. The linked strategy should match the hoisted strategy's behavior here.
Steps To Reproduce
PROJ=/Users/me/tmp-cli-test # any non-/tmp path; /tmp is /private/tmp via symlink and confuses npm
rm -rf "$PROJ"&& mkdir -p "$PROJ/packages/a""$PROJ/packages/b"&&cd"$PROJ"
cat > .npmrc << 'EOF'install-strategy=linkedEOF
cat > package.json << 'EOF'{ "name": "host", "version": "1.0.0", "workspaces": ["packages/a", "packages/b"] }EOFecho'{ "name": "a", "version": "1.0.0" }'> packages/a/package.json
echo'{ "name": "b", "version": "1.0.0" }'> packages/b/package.json
npm install >/dev/null
# Remove workspace b: drop the directory AND the entry in package.json
rm -rf packages/b
node -e "const p=require('./package.json');p.workspaces=['packages/a'];require('fs').writeFileSync('./package.json',JSON.stringify(p,null,2))"test -d packages/b &&echo"before reinstall: present"||echo"before reinstall: gone"
npm install >/dev/null
test -d packages/b &&echo"after reinstall: present"||echo"after reinstall: gone"# Inspect what got recreated
find packages/b
readlink packages/b/node_modules/b
Observed
before reinstall: gone
after reinstall: present
packages/b
packages/b/node_modules
packages/b/node_modules/b
.. # ← packages/b/node_modules/b -> ..
The recreated directory contains only a self-loop symlink. There is no packages/b/package.json and no source files.
Comparison: hoisted strategy
Repeating the same steps without install-strategy=linked (or with install-strategy=hoisted) yields:
before reinstall: gone
after reinstall: gone
Environment
npm: built from npm/cli branch fix/prune-removed-workspace-from-package-lock at commit ea023dd0f
Activity