Skip to content

fix(js): guard against undefined closest node in rehoistNodes#34347

Merged
leosvelperez merged 1 commit intonrwl:masterfrom
kaigritun:fix-prune-lockfile-undefined-closest
Feb 25, 2026
Merged

fix(js): guard against undefined closest node in rehoistNodes#34347
leosvelperez merged 1 commit intonrwl:masterfrom
kaigritun:fix-prune-lockfile-undefined-closest

Conversation

@kaigritun
Copy link
Contributor

Current Behavior

When running @nx/js:prune-lockfile on a monorepo with transitive dependencies that have multiple versions where neither version is reachable from a direct dependency in package.json, the executor throws:

NX   An error occurred while creating pruned lockfile

Original error: Cannot read properties of undefined (reading 'name')

TypeError: Cannot read properties of undefined (reading 'name')
    at switchNodeToHoisted (node_modules/nx/src/plugins/js/lock-file/project-graph-pruning.js:165:31)

Expected Behavior

The lockfile pruning should complete without crashing, even when some transitive dependencies cannot be traced back to a direct dependency.

Root Cause

In rehoistNodes(), when there are multiple nested nodes for a package, the code finds the "closest" node by computing pathLengthToIncoming() for each. However, when none of the nested nodes have a path to any direct dependency in package.json, pathLengthToIncoming() returns undefined for all of them. Since undefined < Infinity is false in JavaScript, closest remains undefined, and then switchNodeToHoisted(undefined, ...) crashes.

Fix

Add a guard to only call switchNodeToHoisted() when a closest node was actually found:

if (closest) {
  switchNodeToHoisted(closest, builder, invBuilder);
}

This allows the pruning to continue - the nested nodes simply won't be rehoisted if no closest node can be determined.

Related Issue

Fixes #34322

Test Added

Added a unit test that verifies rehoistNodes() doesn't crash when nested nodes have no path to package.json dependencies.

@kaigritun kaigritun requested review from a team as code owners February 5, 2026 17:56
@netlify
Copy link

netlify bot commented Feb 5, 2026

Deploy Preview for nx-dev canceled.

Name Link
🔨 Latest commit b6a30d2
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/699edabe98b3eb0008d8325a

@netlify
Copy link

netlify bot commented Feb 5, 2026

Deploy Preview for nx-docs canceled.

Name Link
🔨 Latest commit b6a30d2
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/699edabe53eff00007522880

@MichaelDeBoey
Copy link
Contributor

I'm not making any claims about the quality of their work, but I wanted to let you know that @kaigritun is a fully-autonomous non-human actor
https://socket.dev/blog/ai-agent-lands-prs-in-major-oss-projects-targets-maintainers-via-cold-outreach

@leosvelperez leosvelperez self-assigned this Feb 25, 2026
@nx-cloud
Copy link
Contributor

nx-cloud bot commented Feb 25, 2026

View your CI Pipeline Execution ↗ for commit b6a30d2

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ✅ Succeeded 52m 42s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 3m 14s View ↗
nx-cloud record -- nx-cloud conformance:check ✅ Succeeded 8s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 1s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded <1s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-25 12:24:09 UTC

When transitive dependencies have multiple versions where neither version
is reachable from a direct dependency in package.json, pathLengthToIncoming()
returns undefined for all nested nodes. This leaves 'closest' undefined,
causing switchNodeToHoisted() to crash with:
'Cannot read properties of undefined (reading "name")'

This fix adds a guard to only call switchNodeToHoisted() when a closest
node was actually found.

Fixes nrwl#34322
@leosvelperez leosvelperez force-pushed the fix-prune-lockfile-undefined-closest branch from e859289 to b6a30d2 Compare February 25, 2026 11:19
@leosvelperez leosvelperez enabled auto-merge (squash) February 25, 2026 11:19
@leosvelperez leosvelperez merged commit b46de60 into nrwl:master Feb 25, 2026
15 of 16 checks passed
FrozenPandaz pushed a commit that referenced this pull request Feb 26, 2026
## Current Behavior

When running `@nx/js:prune-lockfile` on a monorepo with transitive
dependencies that have multiple versions where neither version is
reachable from a direct dependency in package.json, the executor throws:

```
NX   An error occurred while creating pruned lockfile

Original error: Cannot read properties of undefined (reading 'name')

TypeError: Cannot read properties of undefined (reading 'name')
    at switchNodeToHoisted (node_modules/nx/src/plugins/js/lock-file/project-graph-pruning.js:165:31)
```

## Expected Behavior

The lockfile pruning should complete without crashing, even when some
transitive dependencies cannot be traced back to a direct dependency.

## Root Cause

In `rehoistNodes()`, when there are multiple nested nodes for a package,
the code finds the "closest" node by computing `pathLengthToIncoming()`
for each. However, when none of the nested nodes have a path to any
direct dependency in package.json, `pathLengthToIncoming()` returns
`undefined` for all of them. Since `undefined < Infinity` is `false` in
JavaScript, `closest` remains `undefined`, and then
`switchNodeToHoisted(undefined, ...)` crashes.

## Fix

Add a guard to only call `switchNodeToHoisted()` when a closest node was
actually found:

```typescript
if (closest) {
  switchNodeToHoisted(closest, builder, invBuilder);
}
```

This allows the pruning to continue - the nested nodes simply won't be
rehoisted if no closest node can be determined.

## Related Issue

Fixes #34322

## Test Added

Added a unit test that verifies `rehoistNodes()` doesn't crash when
nested nodes have no path to package.json dependencies.

(cherry picked from commit b46de60)
FrozenPandaz pushed a commit that referenced this pull request Feb 26, 2026
## Current Behavior

When running `@nx/js:prune-lockfile` on a monorepo with transitive
dependencies that have multiple versions where neither version is
reachable from a direct dependency in package.json, the executor throws:

```
NX   An error occurred while creating pruned lockfile

Original error: Cannot read properties of undefined (reading 'name')

TypeError: Cannot read properties of undefined (reading 'name')
    at switchNodeToHoisted (node_modules/nx/src/plugins/js/lock-file/project-graph-pruning.js:165:31)
```

## Expected Behavior

The lockfile pruning should complete without crashing, even when some
transitive dependencies cannot be traced back to a direct dependency.

## Root Cause

In `rehoistNodes()`, when there are multiple nested nodes for a package,
the code finds the "closest" node by computing `pathLengthToIncoming()`
for each. However, when none of the nested nodes have a path to any
direct dependency in package.json, `pathLengthToIncoming()` returns
`undefined` for all of them. Since `undefined < Infinity` is `false` in
JavaScript, `closest` remains `undefined`, and then
`switchNodeToHoisted(undefined, ...)` crashes.

## Fix

Add a guard to only call `switchNodeToHoisted()` when a closest node was
actually found:

```typescript
if (closest) {
  switchNodeToHoisted(closest, builder, invBuilder);
}
```

This allows the pruning to continue - the nested nodes simply won't be
rehoisted if no closest node can be determined.

## Related Issue

Fixes #34322

## Test Added

Added a unit test that verifies `rehoistNodes()` doesn't crash when
nested nodes have no path to package.json dependencies.

(cherry picked from commit b46de60)
@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@nx/js:prune-lockfile throws "Cannot read properties of undefined (reading 'name')" when transitive dependencies have multiple versions

3 participants