Skip to content

fix: reject nameless added packages before arborist reads edge.spec - #10154

Open
mvanhorn wants to merge 2 commits into
npm:latestfrom
mvanhorn:fix/4819-arborist-missing-name-spec
Open

mvanhorn wants to merge 2 commits into
npm:latestfrom
mvanhorn:fix/4819-arborist-missing-name-spec

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Adding a package whose package.json has no name makes install crash with TypeError: Cannot read properties of undefined (reading 'spec'). The failure comes after fetch and unpack, the command exits 1, and the log shows a node_modules/undefined path. Save can also record a dependency under the key "undefined".

An add spec that arrives without a name is meant to take that name from the fetched manifest. When the manifest name is missing or an empty string, the dependency is stored under the key "undefined" and no outgoing edge is created. Explicit-request tracking and the save path then call edgesOut.get and read edge.spec on that missing edge, which throws.

Changes:

  • After the manifest is loaded, a spec that still has no name and whose manifest name is missing or empty throws EMISSINAME, carrying the raw spec, before that dependency is recorded.
  • New tests cover a versionless named file: add, a nameless manifest, and a mixed add that leaves no "undefined" dependency key.

npm test --workspace @npmcli/arborist passes locally, including the 100% coverage check.

References

Closes #4819

After the manifest is loaded, a spec that still has no name and whose
manifest name is missing or empty throws EMISSINAME, carrying the raw
spec, before that dependency is recorded. Explicit-request collection
adds an edge only when edgesOut returns one. In reify's updateNodes, a
missing outgoing edge is skipped, the same way an edge with no target
already is. New tests cover a versionless named file: add, a nameless
manifest, and a mixed add that leaves no "undefined" dependency key.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With nameless additions now rejected inside #add, these guards don’t appear necessary. Is there another scenario where an edge can legitimately be missing here? If so, could you add a regression test demonstrating why skipping it is correct.

The EMISSINAME check rejects nameless specs before these lookups run,
so the guards were never reached and broke the coverage gate.

@jeffkl jeffkl left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Cannot read properties of undefined (reading 'spec')

2 participants