[BUG] npm install livelocks (100% CPU, infinite CanPlaceDep/canPlacePeers cycle) on dependency graph with cyclic peerDependencies
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 10.1k
- Forks
- 4.7k
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 19
Description
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 -gof the same package works fine (different placement path).--legacy-peer-depscompletes, 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)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce with the provided npm install @deepseek-ai/dsh command, then inspect @npmcli/arborist's can-place-dep.js around canPlacePeers, checkCanPlace, and the peerPath.includes guard, along with the referenced node.js helpers. Trace the cyclic peer-dependency path and add coverage for this graph; done means installation terminates with a completed tree or an ERESOLVE error instead of spinning indefinitely.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nodejs
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100