Skip to content

[BUG] npm install livelocks (100% CPU, infinite CanPlaceDep/canPlacePeers cycle) on dependency graph with cyclic peerDependencies #9934

Description

@KI07SY

Current Behavior

npm install @deepseek-ai/dsh in a fresh directory never completes. The process spins at ~100% CPU indefinitely (verified for 5+ minutes; log output freezes) during dependency tree resolution. npm install -g of the same package completes normally in ~30s.

Expected Behavior

The install completes, or fails with an ERESOLVE error, instead of livelocking.

Steps To Reproduce

mkdir repro && cd repro
npm init -y
npm install @deepseek-ai/dsh
# hangs forever at ~100% CPU, no further output

With --loglevel silly, the last output is a stream of placeDep ROOT @deepseek-ai/... OK for: @deepseek-ai/... lines, then output freezes while CPU stays pegged.

Diagnosis

I attached the inspector (kill -USR1) and sampled the main thread three times via CDP Debugger.pause. All samples show the same repeating stack pattern in arborist (line numbers from @npmcli/arborist 10.0.2 shipped with npm 12.0.2):

getBundler              node.js:528
getBundler              node.js:556   (repeated ~7x)
get inDepBundle         node.js:577
satisfiedBy             can-place-dep.js:113
satisfies               node.js:1166
CanPlaceDep             can-place-dep.js:116
canPlacePeers           can-place-dep.js:390
checkCanPlaceNoCurrent  can-place-dep.js:344
checkCanPlace           can-place-dep.js:161
CanPlaceDep             can-place-dep.js:118
canPlacePeers           can-place-dep.js:390
...

The cycle CanPlaceDep constructor → checkCanPlace()canPlacePeers()new CanPlaceDep(...) never terminates for this dependency graph. The package has ~50 @deepseek-ai/* scoped packages that declare each other as peerDependencies, including cycles (e.g. dsh-agent peers on dsh-llm, dsh-tools peers on both dsh-agent and dsh-llm, dsh-client-runtime peers on many of them). The peerPath.includes(peerEdge.to) guard in canPlacePeers (can-place-dep.js:382) appears insufficient to terminate in this case.

Additional data points:

  • Reproduced with the default registry and with https://registry.npmjs.org (not registry-related).
  • Reproduced with npm 11.16.0 and npm 12.0.2, and with --install-strategy=nested.
  • npm install -g of the same package works fine (different placement path).
  • --legacy-peer-deps completes, but predictably produces a tree that omits the peer dependencies, so the installed CLI cannot load its modules.

Environment

  • npm: 12.0.2 (also reproduced on 11.16.0)
  • Node: v26.0.0
  • OS: macOS 15.7.7 (x86_64)
  • Package: @deepseek-ai/dsh@0.1.1-rc.2 (public, 453 transitive deps)

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