Skip to content

[BUG] linked strategy: removing a dependency leaves a dangling symlink in node_modules #9308

@manzoorwanijk

Description

@manzoorwanijk

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

With install-strategy=linked, removing a dependency does not delete its top-level symlink in node_modules/.

After npm uninstall <pkg> (or removing the entry from package.json and re-running npm install):

  • package.json is updated correctly.
  • The package's entry under node_modules/.store/ is removed.
  • But node_modules/<pkg> is left as a symlink pointing into the now-deleted store path, i.e. a dangling symlink.

require('<pkg>') then fails with Cannot find module '<pkg>', even though node_modules/<pkg> still appears to exist.

Expected Behavior

After removing a dependency, the corresponding symlink in node_modules/ should also be removed so that node_modules/ reflects only the installed packages and contains no broken links.

Steps To Reproduce

mkdir linked-repro && cd linked-repro
npm init -y
npm install eslint --install-strategy=linked

readlink node_modules/eslint
# → .store/eslint@10.3.0-<hash>/node_modules/eslint  ✅

npm uninstall eslint --install-strategy=linked

ls node_modules/.store/
# (empty — store entry correctly removed)

readlink node_modules/eslint
# → .store/eslint@10.3.0-<hash>/node_modules/eslint  ❌ still there

test -e node_modules/eslint && echo EXISTS || echo BROKEN
# BROKEN

node -e "require('eslint')"
# Error: Cannot find module 'eslint'

The same result happens if instead of npm uninstall, the dependency is removed from package.json and npm install --install-strategy=linked is run.

Environment

  • npm: 11.12.1 (latest)
  • Node.js: v24.15.0
  • OS Name: macOS (Darwin 25.4.0 arm64)
  • System Model Name: MacBook Pro
  • npm config:
install-strategy=linked

Root Cause Analysis

Likely the same family of issue as #9106 (dangling symlinks after store hash recalculation): the linked reifier's diff path correctly computes that the .store/<pkg>@… entry should be removed, but does not emit a corresponding action to remove the top-level node_modules/<pkg> symlink that points into it.

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