Skip to main content
DevOps Insightsguides & answers

npm · troubleshooting

npm error ERESOLVE unable to resolve dependency tree

npm could not build a dependency tree that satisfies every package's peerDependencies, so it stopped. The error names the package already in your tree and the package whose peer range excludes it. --force and --legacy-peer-deps make the error go away by installing the very combination the peer range forbids; the fix is to choose versions that agree.

Reproduced on npm 11.12.1, . Where the text says “reproduced”, the behaviour was run on that version, not taken from documentation.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 9 sections

Before you start

  • The project's package.json and package-lock.json, and the full error text, including the lines after While resolving.
  • Network access to the npm registry, for npm view.
  • Permission to change package.json and commit a new lockfile, because the fix is a version change everyone has to share.

Run this first

step 1 of 4
npm install --dry-run

Look for While resolving, Found and Could not resolve dependency: peer … from …

Reproduces the resolution without changing node_modules or the lockfile, and prints the three lines that name the conflict.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

Which header does the error have?

Cause space

4 of 4 still possible

  • Two packages you depend on disagree about a peer versionCommon
  • A plugin has not yet released support for your framework's new major versionCommon
  • The lockfile was written with --legacy-peer-deps, and this install does not use itOccasional
  • The project was last installed with npm 6 or earlierOccasional

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    npm install --dry-run

    Reproduces the resolution without changing node_modules or the lockfile, and prints the three lines that name the conflict.

    Look for While resolving, Found and Could not resolve dependency: peer … from …

  2. Step 2

    npm view <package>@<version> peerDependencies

    Shows the range the declaring package accepts, straight from the registry.

    Look for Whether any release of it accepts the version you have

  3. Step 3

    npm config get legacy-peer-deps

    Shows whether this machine ignores peer dependencies, which decides whether it can even see the conflict.

    Look for true here but not in CI, or the reverse

  4. Step 4

    npm ls --all

    On an installed tree, marks every unmet peer as invalid and exits non-zero, which catches a tree installed with --legacy-peer-deps.

    Look for invalid: lines and npm error code ELSPROBLEMS

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

Two packages you depend on disagree about a peer version

Common

package.json asks for a version of one package that another package's peer range excludes, as react 18 with react-dom 17 does. Often one of them was upgraded without the other.

Confirm

npm view <package>@<version> peerDependencies

Run it for the package named after from in the Could not resolve line. A range that excludes the version shown after Found confirms it

Fix

  • Find a version of the declaring package whose peer range includes what you have: npm view <package>@latest peerDependencies, then older or newer versions as needed.
  • Or move the other package to a version inside the range, if that is the one that drifted.
  • Upgrade them in the same change so the lockfile never holds the mismatched pair.
npm view react-dom@18.3.1 peerDependencies
npm install react-dom@18.3.1

The pair from the example. Reproduced: react-dom 18.3.1 declares react ^18.3.1 and installs cleanly beside react 18.3.1.

A plugin has not yet released support for your framework's new major version

Common

You upgraded a host package, a framework, a linter or a compiler, to a new major version, and a plugin's latest release still lists only older majors in its peer range. No version of the plugin fits, so there is nothing to choose.

Confirm

npm view <plugin>@latest peerDependencies

The host package's new major missing from the range even in the latest release

Fix

  • Stay on the previous major of the host until the plugin catches up, or replace the plugin with one that supports it.
  • If you have tested the combination and accept it, add an overrides entry for that one plugin and record why. It is visible and reviewable, unlike a global flag.
  • Check the plugin's repository for a pre-release or an open issue about the new major before choosing.

The lockfile was written with --legacy-peer-deps, and this install does not use it

Occasional

Someone installed with --legacy-peer-deps, or with legacy-peer-deps=true in a personal .npmrc, and committed the lockfile. An install without the setting, typically npm ci in CI, checks that lockfile and fails with ERESOLVE could not resolve. It looks like CI is broken when the tree always was.

Confirm

npm config get legacy-peer-deps
cat .npmrc

true on the machine that wrote the lockfile and false where the install fails. Reproduced: such a lockfile failed npm ci, and passed once a project .npmrc set legacy-peer-deps=true

Fix

  • Preferably fix the underlying conflict, then regenerate the lockfile without the flag.
  • If the project has decided to live with it, commit legacy-peer-deps=true in the project's .npmrc so every machine and CI resolve the same way, and record why.

The project was last installed with npm 6 or earlier

Occasional

npm 3 to 6 did not install peerDependencies, so conflicts were at most warnings. A project last resolved that way fails the first time npm 7 or later builds its tree, and every conflict it has carried surfaces at once.

Confirm

npm --version
grep -m1 lockfileVersion package-lock.json

lockfileVersion 1, which npm's documentation says is the format used by npm 5 and 6

Fix

  • Resolve the conflicts one by one with the first two causes; do not pin npm 6, which no longer receives updates.
  • Commit the regenerated lockfile, which npm 9 and later write as lockfileVersion 3.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Some packages only work alongside a particular version of another package, and say so in a list called peerDependencies. React DOM 17, for example, needs React 17. When your project asks for a combination that breaks one of those rules, npm refuses to install anything rather than guess. The error tells you which package wanted which version, so the job is to pick versions that fit together.

A peer conflict, and what the suggested flags actually install

Reproduced with npm 11.12.1 on macOS in an empty project whose package.json asked for react 18.3.1 and react-dom 17.0.2. react-dom 17.0.2 declares a peer dependency on react 17.0.2. --dry-run resolves the tree without installing it. The log paths at the end are shortened.

Command

npm install --dry-run

Output

npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error
npm error While resolving: eresolve-repro@1.0.0
npm error Found: react@18.3.1
npm error node_modules/react
npm error   react@"18.3.1" from the root project
npm error
npm error Could not resolve dependency:
npm error peer react@"17.0.2" from react-dom@17.0.2
npm error node_modules/react-dom
npm error   react-dom@"17.0.2" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
npm error …-eresolve-report.txt

How to read it

  • Found: react@18.3.1 is what is already in the tree, and the indented line says who asked for it: the root project, meaning your package.json.
  • Could not resolve dependency: peer react@"17.0.2" from react-dom@17.0.2 names the package with the unmet requirement and exactly what it requires.
  • The last line is honest about the flags: they accept an incorrect resolution. Run here, --legacy-peer-deps and --force both succeeded, and so did an overrides entry pointing react-dom at the root react. All three installed react-dom 17.0.2 next to react 18.3.1.
  • The fix was a version that agrees: react-dom 18.3.1 declares react: ^18.3.1, and the same install then succeeded with no flags.

Words used on this page

peerDependencies
Packages a package needs but expects you to provide, such as a plugin needing its host framework. Since npm 7 they are installed by default, so a conflict between them stops the install.
ERESOLVE
npm's error code for a dependency tree it cannot build. It is not a network or registry failure.
legacy-peer-deps
A setting that makes npm ignore peerDependencies entirely, as npm 3 to 6 did. npm's documentation says it is not recommended.
overrides
A package.json field that forces a version somewhere in the tree. It changes what is installed; it does not make the combination compatible.
Lockfile
package-lock.json, which records the exact tree. npm ci installs exactly that tree and fails if it cannot.
What is actually happening

Since npm 7, peerDependencies are installed by default, as npm's package.json documentation says. npm therefore has to find one tree in which every package's peer range is satisfied. When no such tree exists, it stops with ERESOLVE instead of installing something that breaks those ranges.

The message has a fixed shape. While resolving names the package being placed; Found names the version already in the tree and who asked for it; Could not resolve dependency names the peer requirement that cannot be met and who declared it. Read those three lines and you know both sides of the conflict.

There are two headers. unable to resolve dependency tree comes from building a tree from package.json. could not resolve comes from checking an existing lockfile, and in the reproduction here it appeared when npm ci met a lockfile that had been written with --legacy-peer-deps.

The flags the message offers do not resolve anything. They tell npm to stop checking, and you get the same incompatible pair, now installed. Whether that pair works at runtime is something npm can no longer tell you.

How to tell this is your problem
WhereWhat you see
npm install outputnpm error ERESOLVE unable to resolve dependency tree
npm ci output, with an existing lockfilenpm error ERESOLVE could not resolve
Older npm versionsnpm ERR! code ERESOLVE
The lines after the headerCould not resolve dependency: peer react@"17.0.2" from react-dom@17.0.2
npm ls on a tree installed with --legacy-peer-depsinvalid: "17.0.2" from node_modules/react-dom, and npm error code ELSPROBLEMS

How to know it is actually fixed

  • npm ci succeeds in a clean checkout with no flags and no legacy-peer-deps setting.
  • npm ls --all exits 0, with no invalid lines.
  • The application's tests pass on the new versions, since a peer range is a promise from the maintainer, not a test of your code.

Stopping it happening again

  • Upgrade a framework together with its plugins, and check each plugin's peer range with npm view before the upgrade, not after.
  • Run npm ls --all in CI so a tree with unmet peers fails there, whoever installed it and with whatever flags.
  • Keep any legacy-peer-deps or overrides decision in the repository, with the reason, so it is reviewed and revisited.

Security considerations

  • --force does far more than accept a peer conflict. npm's documentation lists a dozen protections it removes, including engines checks and npm audit fix staying within your version ranges. Never make it the default in CI.
  • A peer conflict is often the first sign that a dependency is no longer maintained, because it has not published a release for your framework's current major version. An abandoned package will not get security fixes either, so check when it last released with npm view <package> time.modified.
  • Do not switch CI from npm ci to npm install to get past the error. npm install can rewrite the lockfile, so CI would build a different tree from the one that was reviewed.
  • If you accept a conflict deliberately, scope it with overrides for the one package and write down why, rather than setting legacy-peer-deps for the whole project, which also hides every future conflict.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it