Skip to content

Arborist crashes with "Cannot read properties of null (reading 'matches')" on a Link with a null target #9459

Description

@ljharb

Summary

Link.matches (@npmcli/arborist/lib/node.js:1183) dereferences this.target without a null check:

if (this.isLink) {
  return node.isLink && this.target.matches(node.target)
}

When node_modules contains store-style symlinks whose targets npm hasn't loaded as nodes - e.g. a tree populated by bun (node_modules/.bun/...) or vlt (node_modules/.vlt/...), neither of which writes node_modules/.package-lock.json - this.target is null, so any npm install crashes mid-reify with an unhandled TypeError instead of a clean, actionable error.

Steps to reproduce

  1. In any npm workspace monorepo, install deps with another package manager: vlt install (or bun install).
  2. Run npm install.

Actual

TypeError: Cannot read properties of null (reading 'matches')
    at Link.matches (@npmcli/arborist/lib/node.js:1183:41)
    at Link.canDedupe (lib/node.js:1127:15)
    at PlaceDep.pruneDedupable (lib/place-dep.js:426:14)
    at new PlaceDep (lib/place-dep.js:278:14)
    at #buildDepStep (lib/arborist/build-ideal-tree.js:933:18)
    at async Arborist.buildIdealTree (lib/arborist/build-ideal-tree.js:170:7)
    at async Arborist.reify (lib/arborist/reify.js:111:5)
    at async Install.exec (lib/commands/install.js:146:5)

Expected

A clean error (e.g. "node_modules was not installed by npm"), not an unhandled TypeError. Minimal fix: guard the link branch, e.g. return node.isLink && !!this.target && this.target.matches(node.target).

Alternatively, regenerate the hidden lockfile whenever it's absent.

Environment

npm 11.13.0, Node 26 (also reproduced on Node 22/24 in CI).

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