Skip to content

[BUG] Workspace file: dependency on a non-workspace package is silently skipped with install-strategy=linked #9589

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

When a workspace declares a file: dependency that points to a non-workspace local package (a directory outside the project's workspaces globs) and the project is installed with install-strategy=linked, the dependency is silently skipped. npm install reports up to date / added 0 packages, no node_modules entry is created for the dep, and the workspace cannot resolve it at runtime (require throws MODULE_NOT_FOUND). No error or warning is printed.

The key trigger is that the file: target is not itself a workspace. A workspace file: dep that points to another workspace (e.g. "@scope/b": "file:../b" where b is under packages/* — the common monorepo case, e.g. Gutenberg) works fine, because the target is matched by n.isWorkspace. The bug only surfaces for file: targets outside the workspace set — which is exactly the #9115 case (npm --workspace=<ws> link <external-path>), and any workspace depending on a local non-workspace folder.

This is also distinct from the already-fixed #9166 / #9210 (which crashed with ENOENT for file: deps in a non-workspace project). Those now work; this is the residual case where the consumer is a workspace and the target is not.

So install-strategy=linked is not a viable workaround for #9115.

What works vs what fails (linked strategy)

Scenario Result
Workspace file: dep → non-workspace local package ❌ silently skipped (not installed, no error)
Workspace file: dep → another workspace (e.g. Gutenberg file:../i18n) ✅ installed + resolves
Root-declared file: dep (workspaces present, any target) ✅ installed + resolves
file: dep declared by root in a non-workspace project ✅ installed + resolves
Registry dep declared by a workspace ✅ installed into node_modules/.store + symlinked into the workspace

Expected Behavior

A file: dependency declared by a workspace should be symlinked into that workspace's node_modules under install-strategy=linked, identical to a registry dependency and identical to the hoisted strategy. If it genuinely cannot be installed, npm must error — not silently report success.

Steps To Reproduce

rm -rf /tmp/repro9115 && mkdir -p /tmp/repro9115/packages/ws-a /tmp/repro9115/local-dep

cat > /tmp/repro9115/package.json << 'EOF'
{ "name": "mono", "version": "1.0.0", "workspaces": ["packages/*"] }
EOF

cat > /tmp/repro9115/local-dep/package.json << 'EOF'
{ "name": "local-dep", "version": "1.0.0" }
EOF

cat > /tmp/repro9115/packages/ws-a/package.json << 'EOF'
{ "name": "ws-a", "version": "1.0.0", "dependencies": { "local-dep": "file:../../local-dep" } }
EOF

cd /tmp/repro9115
npm install --install-strategy=linked
# => "up to date, audited 5 packages" — but nothing is installed

find . -type d -name node_modules          # => (no node_modules at all)
node -e "require.resolve('local-dep/package.json', { paths: ['/tmp/repro9115/packages/ws-a'] })"
# => Error: Cannot find module 'local-dep/package.json'

Works with hoisted strategy (control)

rm -rf /tmp/repro9115/node_modules /tmp/repro9115/package-lock.json
cd /tmp/repro9115
npm install
node -e "console.log(require.resolve('local-dep/package.json', { paths: ['/tmp/repro9115/packages/ws-a'] }))"
# => /private/tmp/repro9115/local-dep/package.json

Environment

  • npm: 12.0.0-pre.1 (reproduced on latest; line unchanged across recent branches)
  • Node.js: v24.17.0
  • OS Name: macOS (Darwin 25.5.0)
  • npm config:
install-strategy=linked

Related: #9115, #9166, #9210.

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