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-links fails when local package has nested local dependencies #8342
When installing a local package with --install-links, if that package has its own local dependencies, the installation fails. Is this behavior by design?
In this example, package b depends on package a, both located in sibling directories:
The npm CLI attempts to resolve ../a from within node_modules/b or node_modules/a, which does not exist. This results in an ENOENT error:
$ cd mainpkg && npm install --install-links ../b
npm error code ENOENT
npm error syscall open
npm error path /home/mukai/Documents/mainpkg/node_modules/a/package.json
npm error errno -2
npm error enoent Could not read package.json: Error: ENOENT: no such file or directory, open '/home/mukai/Documents/mainpkg/node_modules/a/package.json'
npm error enoent This is related to npm not being able to find a file.
npm error enoent
npm error A complete log of this run can be found in: /home/mukai/.npm/_logs/2025-06-03T11_28_04_990Z-debug-0.log
Expected Behavior
The dependency a, as listed in b's package.json, should be resolved relative to b itself (i.e., ../a from b). As a result, the structure of mainpkg/node_modules should look like this:
$ tree mainpkg/node_modules
mainpkg/node_modules
├── a -> ../../a
└── b -> ../../b
3 directories, 0 files
Steps To Reproduce
$ mkdir a b mainpkg
$ echo '{"name":"a"}' > a/package.json
$ echo '{"name":"b"}' > b/package.json
$ cd b && npm install ../a && cd ../
$ cd mainpkg && npm init --yes
$ npm install --install-links ../b
Environment
npm: 11.4.1
Node.js: v22.14.0
OS Name: Ubuntu 24.04
System Model Name: ThinkPad-X1-Carbon-7th
npm config:
; "user" config from /home/mukai/.npmrc
//registry.npmjs.org/:_authToken = (protected)
; node bin location = /home/mukai/.nvm/versions/node/v22.14.0/bin/node; node version = v22.14.0; npm local prefix = /home/mukai/Documents/mainpkg; npm version = 11.4.1; cwd = /home/mukai/Documents/mainpkg; HOME = /home/mukai; Run `npm config ls -l` to show all defaults.
@owlstronaut Sorry, but I'm not entirely sure if PR #8436 actually resolves this issue. It’s true that npm install --install-links ../b now appears to succeed. However, once the code in package b tries to import a, won’t it still fail to find package a?
For example:
$ mkdir a && echo '{"name":"a","main":"index.js"}' > a/package.json && echo 'export const A = "A";' > a/index.js
$ mkdir b && echo '{"name":"b","main":"index.js","dependencies":{"a":"file:../a"}}' > b/package.json && echo 'import {A} from "a";export const fn = () => console.log(A);' > b/index.js
$ mkdir mainpkg && cd mainpkg && echo '{}' > package.json && npm install --install-links ../b # this will succeed properly
$ node -e "const {fn}=await import('b');"
node:internal/modules/package_json_reader:256
throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'a' imported from /home/mukai/temp/mainpkg/node_modules/b/index.js
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:256:9)
at packageResolve (node:internal/modules/esm/resolve:768:81)
at moduleResolve (node:internal/modules/esm/resolve:854:18)
at defaultResolve (node:internal/modules/esm/resolve:984:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:780:12)
at #cachedDefaultResolve (node:internal/modules/esm/loader:704:25)
at ModuleLoader.resolve (node:internal/modules/esm/loader:687:38)
at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:305:38)
at ModuleJob._link (node:internal/modules/esm/module_job:175:49) {
code: 'ERR_MODULE_NOT_FOUND'
}
@u1f992 Could you give the same a try with 11.5.2. I'm not sure why, but it seems the changelog didn't pick up this fix. It looks to me like your example works in 11.5.2
Activity
alexsch01 commentedon Jun 3, 2025
FYI: this issue is reproducible on npm versions before npm 11 too
(I tested on npm 10.8.2)
u1f992 commentedon Jul 29, 2025
@owlstronaut Sorry, but I'm not entirely sure if PR #8436 actually resolves this issue. It’s true that
npm install --install-links ../bnow appears to succeed. However, once the code in packagebtries to importa, won’t it still fail to find packagea?For example:
Environment:
owlstronaut commentedon Jul 29, 2025
@u1f992 thanks for the example. I should be able to take another look at this next week
owlstronaut commentedon Aug 19, 2025
@u1f992 Could you give the same a try with 11.5.2. I'm not sure why, but it seems the changelog didn't pick up this fix. It looks to me like your example works in 11.5.2
u1f992 commentedon Aug 20, 2025
@owlstronaut Thank you for the follow-up. Unfortunately, the issue still seems to persist. As shown below, it looks like the same error occurs.
u1f992 commentedon Nov 21, 2025
@owlstronaut Thank you for the fix! This indeed solved my issue.
By the way, is it by design that transitive external file dependencies are only handled when
--install-linksis used?The original purpose of
--install-linksis to installfile:protocol dependencies by copying instead of linking. That’s why, with the patch you applied this time, the packages are installed like this:On the other hand, without
--install-links, onlybis still installed as a symbolic link. Naturally, in this case, importingbwill fail.It seems like npm could just create a symbolic link to
../afrom../../beven without--install-links. Something like this: