Skip to content

[BUG] npm install -g --allow-scripts=<pkg> with no package spec crashes in arborist diffTrees #10052

Description

@fabianoflorentino

Is there an existing issue for this?

  • I have searched the existing issues
  • I believe this is a new issue

Related: #9835 (npm's own remediation prompt suggests the exact command that crashes), #6006 (same error message, different trigger)

This issue exists in the latest npm version

  • I am using the latest npm

Current Behavior

npm install -g --allow-scripts=<pkg> with no positional package spec always crashes with Cannot destructure property 'name' of '.for' as it is undefined. — including the exact command npm itself prints in the install-scripts remediation warning:

npm warn install-scripts Run `npm install -g --allow-scripts=ffmpeg-static` to allow these scripts once,
                 or `npm config set allow-scripts=ffmpeg-static --location=user` to allow them for all global installs.

This makes the documented one-off escape hatch for a blocked install script unusable, and the npm config set --location=user alternative is a permanent policy change for a one-time need.

npm error Cannot destructure property 'name' of '.for' as it is undefined.
npm error A complete log of this run can be found in: ~/.npm/_logs/...-debug-0.log
verbose stack TypeError: Cannot destructure property 'name' of '.for' as it is undefined.
verbose stack     at [diffTrees] (.../@npmcli/arborist/lib/arborist/reify.js:454:20)
verbose stack     at Arborist.reify (.../@npmcli/arborist/lib/arborist/reify.js:138:29)
verbose stack     at async Install.exec (.../npm/lib/commands/install.js:176:5)
verbose stack     at async Npm.exec (.../npm/lib/npm.js:194:9)

Expected Behavior

Either the install should succeed, or install.js should not feed a synthetic . spec into Arborist in this case. Failing with a TypeError is never acceptable.

Steps To Reproduce

Deterministic, and not specific to any package:

$ npm install -g --allow-scripts=left-pad
npm error Cannot destructure property 'name' of '.for' as it is undefined.

$ npm install -g --allow-scripts=left-pad left-pad     # works
added 1 package in 249ms

The same holds for the space-separated form (--allow-scripts left-pad), and for any package name.

Root cause

install.js substitutes a . spec when a global install has no positional args, so that npm reifies the global tree:

// npm/lib/commands/install.js:138
if (isGlobalInstall && !args.length) {
  args = ['.']
}

That spec is passed to Arborist as add, and ends up in _resolvedAdd. The global tree root has no dependency entry for it, so the edgesOut lookup misses and undefined is added to #explicitRequests:

// @npmcli/arborist/lib/arborist/build-ideal-tree.js:651
for (const spec of this[_resolvedAdd]) {
  if (spec.tree === tree) {
    this.#explicitRequests.add(tree.edgesOut.get(spec.name))   // <-- undefined
  }
}

diffTrees then destructures it under the global branch:

// @npmcli/arborist/lib/arborist/reify.js:449
if (this.options.global && this.explicitRequests.size) {
  ...
  for (const { name } of this.explicitRequests) {   // <-- TypeError

Confirmed by instrumenting Set.prototype.add during the crash; the undefined originates at build-ideal-tree.js:653.

Passing a real spec masks the bug, because that spec does get an edge in edgesOut — which is also why the workaround below works.

Suggested fix

Guard the lookup in build-ideal-tree.js:651 (and the globalExplicitUpdateNames loop right below it, which has the same shape):

for (const spec of this[_resolvedAdd]) {
  if (spec.tree === tree) {
    const edge = tree.edgesOut.get(spec.name)
    if (edge) {
      this.#explicitRequests.add(edge)
    }
  }
}

Workaround

Repeat the package as a positional spec:

npm install -g --allow-scripts=ffmpeg-static ffmpeg-static

Note that a project .npmrc allow-scripts is not consulted for global installs, so the npm config set ... --location=user route is the only other option, and it is global/permanent.

Environment

  • npm -v: 12.0.2
  • node -v: v26.8.1
  • OS: Arch Linux, kernel 7.2.7-arch1-1
  • Prefix: asdf-installed nodejs 26.8.1

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