Scoped package installed via local path (`npm i -g .`) produces broken symlinks
Bug Description
When installing a scoped package from a local path using npm i -g ., the installed binary fails to run with No such file or directory (os error 2). The shim executes but the underlying symlink in the package image directory points to a non-existent path.
Root Cause
DirectInstall::new (crates/volta-core/src/tool/package/mod.rs) creates the staging directory with NeedsScope::No because the package name is unknown upfront. For scoped packages (e.g. @scope/pkg), the final image directory is one level deeper than the staging directory:
- Staging:
$VOLTA_HOME/tmp/image/packages/{tempdir}/lib/node_modules/@scope/ - Final image:
$VOLTA_HOME/tools/image/packages/@scope/pkg/lib/node_modules/@scope/
npm creates a relative symlink inside the staging node_modules/@scope/ pointing back to the local source directory. The relative path is computed against the staging depth. After persist_install renames the staging directory into the final image location (which is one level deeper), the relative symlink resolves to a path inside $VOLTA_HOME that does not exist.
Reproduction Steps
- Create a local scoped package with a
binentry, e.g.@scope/my-cliwith"bin": { "my-cli": "./bin/my-cli.js" }. - From the package directory, run:
npm i -g . - Attempt to run the installed binary:
my-cli --help
Expected Behavior
The binary runs successfully.
Actual Behavior
Volta v2.0.2
Could not execute command.
See `volta help install` and `volta help pin` for info about making tools available.
Error cause: No such file or directory (os error 2)Inspecting the symlink confirms it points to a non-existent path inside $VOLTA_HOME (the relative .. count is one short for the final image depth).
Scope
- Affected:
npm i -g .(and likelyyarn global add .) with scoped local packages. - Not affected:
- Non-scoped local packages (no scope nesting level involved).
- Remote package installs (downloaded files, not symlinks).
npm link(usesfor_npm_link→with_name, which setsNeedsScope::Yesand matches the final depth).
Environment
- Volta: 2.0.2
- OS: Linux
- Node: 20.x
Source: volta-cli/volta