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
bin entry, e.g. @scope/my-cli with "bin": { "my-cli": "./bin/my-cli.js" }.
- From the package directory, run:
- Attempt to run the installed binary:
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 likely yarn 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 (uses for_npm_link → with_name, which sets NeedsScope::Yes and matches the final depth).
Environment
- Volta: 2.0.2
- OS: Linux
- Node: 20.x
Bug Description
When installing a scoped package from a local path using
npm i -g ., the installed binary fails to run withNo 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 withNeedsScope::Nobecause 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:$VOLTA_HOME/tmp/image/packages/{tempdir}/lib/node_modules/@scope/$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. Afterpersist_installrenames the staging directory into the final image location (which is one level deeper), the relative symlink resolves to a path inside$VOLTA_HOMEthat does not exist.Reproduction Steps
binentry, e.g.@scope/my-cliwith"bin": { "my-cli": "./bin/my-cli.js" }.npm i -g .Expected Behavior
The binary runs successfully.
Actual Behavior
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
npm i -g .(and likelyyarn global add .) with scoped local packages.npm link(usesfor_npm_link→with_name, which setsNeedsScope::Yesand matches the final depth).Environment