Skip to content

Scoped package installed via local path (npm i -g .) produces broken symlinks #2113

Description

@Bacra

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

  1. Create a local scoped package with a bin entry, e.g. @scope/my-cli with "bin": { "my-cli": "./bin/my-cli.js" }.
  2. From the package directory, run:
    npm i -g .
  3. 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 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_linkwith_name, which sets NeedsScope::Yes and matches the final depth).

Environment

  • Volta: 2.0.2
  • OS: Linux
  • Node: 20.x

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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