Skip to content

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

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions