Skip to content

[BUG] npm link is broken with install-strategy=linked #9166

@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

npm link (both npm link <pkg> via global and npm link <path> via local path) crashes with ENOENT when using install-strategy=linked. The linked strategy tries to extract the linked package into the .store/ directory using pacote.extract(), but the file: relative path is resolved from the store entry location (deep inside node_modules/.store/pkg@version-hash/node_modules/pkg/) instead of from the project root, resulting in a wrong absolute path.

Error output (via local path)

npm warn reify The "linked" install strategy is EXPERIMENTAL and may contain bugs.
npm error code ENOENT
npm error path <NVM_DIR>/lib/node_modules/my-linked-pkg/package.json
npm error enoent Could not read package.json

The local-path flow (npm link ../link-pkg) looks for the package in the global node_modules instead of the local path.

Error output (via global link)

npm warn tarball tarball data for my-linked-pkg@file:../../link-pkg (null) seems to be corrupted. Trying again.
npm warn tarball tarball data for my-linked-pkg@file:../../link-pkg (null) seems to be corrupted. Trying again.
npm error code ENOENT
npm error path /private/link-pkg/package.json
npm error enoent Could not read package.json

The global-link flow (npm link my-linked-pkg) tries to extract the package into .store/ using pacote.extract(), but the file: relative path is resolved from the store entry location instead of the project root, producing a wrong absolute path (/private/link-pkg instead of /private/tmp/link-pkg).

Expected Behavior

npm link should create a symlink in node_modules/ pointing to the linked package, identical to how it works with hoisted strategy. Linked packages should NOT be extracted into the .store/ — they should remain as symlinks since the whole point of npm link is to use the local source directly.

Steps To Reproduce

Via local path

rm -rf /tmp/link-pkg /tmp/link-app
mkdir -p /tmp/link-pkg /tmp/link-app

cat > /tmp/link-pkg/package.json << 'EOF'
{ "name": "my-linked-pkg", "version": "1.0.0", "main": "index.js" }
EOF
echo "module.exports = 'hello'" > /tmp/link-pkg/index.js

cat > /tmp/link-app/package.json << 'EOF'
{ "name": "link-app", "version": "1.0.0", "dependencies": { "nopt": "^7.0.0" } }
EOF

cd /tmp/link-app
npm install --install-strategy=linked --ignore-scripts
npm link ../link-pkg --install-strategy=linked
# ERROR: ENOENT Could not read package.json

Via global link

rm -rf /tmp/link-pkg /tmp/link-app
# ... (set up link-pkg and link-app as above)
cd /tmp/link-pkg && npm link           # registers globally (works)
cd /tmp/link-app && npm install --install-strategy=linked --ignore-scripts
npm link my-linked-pkg --install-strategy=linked
# ERROR: ENOENT Could not read package.json

Works with hoisted strategy

rm -rf /tmp/link-app/node_modules /tmp/link-app/package-lock.json
cd /tmp/link-app
npm install --ignore-scripts
npm link ../link-pkg   # works fine, creates symlink
node -e "console.log(require('my-linked-pkg'))"  # => "hello"

Root Cause

The isolated reifier in isolated-reifier.js treats ALL dependencies uniformly — including file: dependencies from npm link. It generates a store key and tries to extract the package into .store/pkg@version-hash/node_modules/pkg/ using pacote.extract(). The file: relative path stored in the lockfile is resolved relative to the store entry path rather than the project root, producing a wrong absolute path.

file: dependencies from npm link should be handled as symlinks (like workspace dependencies), not extracted into the store.

Environment

  • npm: 11.12.1
  • Node.js: v22.20.0
  • OS Name: macOS (Darwin 25.4.0)
  • npm config:
install-strategy=linked

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    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