npm / npm/cli

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

Open
#9,934 0 comments 0 reactions 0 assignees View on GitHub

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 -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)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.