← Debugging Guides

阅读中文版本

npm ERESOLVE peer dependency conflict — Resolve Without --force

Diagnose npm ERESOLVE errors with npm ls, npm explain, and peerDependencies metadata, then align versions or use targeted overrides instead of disabling peer checks.

beginnerdebuggingnpmdependencies

Symptoms

  • npm ERR! code ERESOLVE
  • npm ERR! ERESOLVE unable to resolve dependency tree
  • The error names a peer dependency range such as react@^19.0.0
  • Installation works with --legacy-peer-deps but fails in CI

Possible causes

  • A library declares a peer range that does not include the installed major version
  • Two plugins require incompatible versions of the same framework
  • The lockfile and package.json disagree after a manual edit or merge
  • An old transitive package pins a peer that was never updated

Diagnosis steps

Read the full resolution tree in the error

npm install 2>&1 | sed -n '/ERESOLVE/,/npm ERR!/p' | head -40

Interpretation

The Found and Could not resolve lines name the installed version and the required peer range. The 'While resolving' line shows which parent pulled it in.

Inspect what is installed

npm ls react react-dom

Interpretation

INVALID or UNMET PEER entries identify the broken edge. An empty tree means dependencies were never installed successfully.

Explain why a package is present

npm explain react

Interpretation

The chain shows whether react is a direct dependency, a peer of a plugin, or a transitive dependency. This determines which package you can upgrade.

Check the declared peer range

npm view some-ui-kit@latest version peerDependencies --json

Interpretation

Compare the declared range with the installed framework. If the latest release still excludes your version, the library is not compatible yet.

Root cause

npm 7 and later install peer dependencies automatically and fail when no version can satisfy every declared range. The conflict is real metadata: a plugin expects React 19 while the app runs React 18, or two packages require mutually exclusive versions of a shared library. npm refuses to guess because the resulting tree could break at runtime.

Fix

Prefer upgrading the app or the plugin so the peer ranges overlap, and update react and react-dom together. When a transitive package lags, add a targeted package.json overrides entry rather than a global flag. Use --legacy-peer-deps only as a temporary unblock, and never use --force to install a tree npm has already declared invalid.

Risk note

overrides changes the version every dependent receives and can break packages that genuinely need the old API. --legacy-peer-deps reproduces npm 6 behavior, skips peer installation, and hides incompatibilities that surface later as runtime errors. Deleting package-lock.json can silently upgrade unrelated dependencies.

Verify the fix

Run npm ls and confirm no INVALID or UNMET PEER entries remain, then run the test suite and a production build. Install from a clean clone with npm ci to prove the lockfile captures the resolution.

ERESOLVE is npm refusing to guess

npm 7 and later treat peer dependencies as installable requirements. If a plugin declares peer react@^19.0.0 and the app has React 18, npm cannot produce a tree that satisfies both:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! Found: [email protected]
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^19.0.0" from [email protected]

The conflict is metadata, not a corrupt cache. Clearing node_modules will not change it.

Find the edge that conflicts

npm ls react react-dom
npm explain react
npm view some-ui-kit@latest peerDependencies --json

npm explain prints the dependency chain, which tells you whether you can upgrade the parent or need an override for a transitive package. Check whether a newer plugin release supports your framework before forcing anything.

Fix at the source

  • Upgrade the app and the plugin to overlapping majors, moving react and react-dom together.
  • Replace an abandoned plugin with a maintained alternative.
  • Use a narrow override when a transitive package lags:
{
  "overrides": {
    "some-ui-kit": {
      "react": "$react"
    }
  }
}

--legacy-peer-deps is an escape hatch for an urgent deploy, not a resolution. Record why it was needed and remove it once versions align.

Verify

npm ls should show no INVALID or UNMET PEER entries, and tests plus a production build should pass. Run npm ci in a clean directory to confirm the lockfile records the same tree CI will install. If the app builds only with the flag, the incompatibility is still present and will eventually appear at runtime.