npm ERR! ERESOLVE: “unable to resolve dependency tree,” explained and fixed

Since npm 7, npm refuses to install when packages' peer dependency requirements conflict — one package wants React 17, another demands React 18, and npm won't guess. ERESOLVE is npm protecting the tree from a combination its own rules say is invalid. The error output includes a plain-English report of exactly which packages are fighting.

Read the report first

The lines under ERESOLVE name the conflict precisely: “While resolving: your-app”, “Found: react@…”, “Could not resolve dependency: peer react@… from …”. Two packages and two version ranges — that's the entire dispute. npm also writes the full report to a file it names in the error (eresolve-report.txt in the npm cache logs folder).

The fix, in order of correctness

  1. Align the versions. Upgrade (or pin) the packages so their peer ranges overlap — usually updating the lagging plugin/library to a release that supports the newer framework version. This is the real fix and the one that survives future installs.
  2. Remove the abandoned package. A common root: an unmaintained dependency stuck on old peer ranges. Replacing it with a maintained equivalent clears the conflict permanently.
  3. Use --legacy-peer-deps knowingly: npm install --legacy-peer-deps restores npm 6 behaviour (peers warned about, not enforced). Legitimate when the conflicting package works fine in practice and no updated release exists — common with older project templates. It is a documented mode, not a hack, but it means you own verifying the combination actually runs.
  4. --force is the blunter sibling — it installs despite conflicts and can leave a broken tree. Prefer legacy-peer-deps; reserve force for throwaway experiments.
  5. Make it permanent if the team agrees: add legacy-peer-deps=true to the project's .npmrc so every install (and CI) behaves the same — surprises belong in code review, not in CI logs.
Deleting node_modules and package-lock.json doesn't resolve ERESOLVE — the conflict is in the version requirements themselves, not in leftover state. A clean install hits the same wall. Fix ranges, or consciously choose the legacy mode.

If it still happens

Check for a second conflict hiding behind the first — npm reports them one layer at a time. Also confirm the npm version in play (npm -v): a project built under npm 6 (which tolerated these trees) often meets ERESOLVE for the first time on a newer machine or CI image. The overrides field in package.json is the surgical last resort for pinning one transitive peer — powerful, and worth a comment in the code explaining why it exists.

Common questions

Is --legacy-peer-deps dangerous? It removes a safety check, so the installed combination is unverified by npm's rules. In practice it's widely used for known-good ecosystems (older React tooling especially). The risk is real but modest; the alternative of never installing is worse.

Why did this start suddenly? A dependency released a new major version, or npm itself was upgraded. Nothing in your code changed — the negotiation between packages did.

Related errors

EADDRINUSE · TypeError: cannot read properties · Failed to push some refs