nodeseverity: workaround
ERESOLVE

npm ERR! ERESOLVE unable to resolve dependency tree

ERESOLVE unable to resolve dependency tree

90% fixable~10 mindifficulty: intermediate

Verified against npm 11 docs (cli/commands/npm-install.md), npm RFC #39 (peer deps), Stack Overflow #66239691 · Updated April 2026

> quick_fix

A package requires a peer-dependency version that conflicts with another package in your tree. Try `npm install --legacy-peer-deps` to restore npm-6 behaviour, or update the conflicting packages to compatible versions.

# Quick escape hatch (npm 7+)
npm install --legacy-peer-deps

# Or accept pre-release versions
npm install --force

# Better: find the conflict and upgrade
npm ls <conflicting-package>

What causes this error

npm 7 and later strictly enforce peer dependencies. If package A wants React 17 as a peer and package B wants React 18, npm refuses to install either version because it would violate one package's contract. In npm 6, peer deps were only warned about — npm 7+ made them blocking.

> advertisementAdSense placeholder

How to fix it

  1. 01

    step 1

    Read the error output to find the conflict

    ERESOLVE shows `Found: X@version` and `Could not resolve Y@version` — those are the conflicting packages.

  2. 02

    step 2

    Try --legacy-peer-deps first

    This restores npm 6 behaviour and usually works. Safe for most React, Vue, and Angular apps where the peer conflict is a known ecosystem lag.

    npm install --legacy-peer-deps
  3. 03

    step 3

    For a real fix, update the conflicting package

    Check which package requires the stricter peer. Often it's a transitive dep — upgrade your direct dep to a newer version that has a compatible peer.

  4. 04

    step 4

    Pin versions with overrides if upstream won't update

    In package.json, use the `overrides` field (npm 8.3+) to force a specific version of a transitive dep.

    {
      "overrides": {
        "react": "$react"
      }
    }

Why ERESOLVE happens at the runtime level

npm 7+ replaced the lenient peer-dep handling of npm 6 with Arborist, a strict tree-resolver that treats peerDependencies as hard constraints. When Arborist builds the ideal dependency tree, it intersects every package's peer requirements with the versions already chosen for direct dependencies. If no single version satisfies all constraints, Arborist refuses to write package-lock.json and exits with ERESOLVE, listing the conflicting packages and the unsatisfied range. The check happens before any download, so the error is always a graph-resolution problem and never a network or cache issue.

Common debug mistakes for ERESOLVE

  • Deleting node_modules and re-running npm install, Arborist resolves from package.json plus package-lock.json, and the lockfile rewrite is what's actually failing, so deleting node_modules changes nothing.
  • Adding the conflicting package to dependencies expecting it to win, peer constraints are evaluated against the entire tree, not by hoisting precedence, so direct-deps don't override peer requirements.
  • Running npm install --force in production CI as a permanent fix, --force writes a lockfile with constraint violations baked in, so the runtime crash now happens on user devices instead of at build time.
  • Switching to yarn classic and assuming it 'works', yarn 1 uses the same lenient model as npm 6 and silently lets the conflict ship; yarn 3+ has its own peer-dep enforcement.
  • Using overrides without understanding it's a tree rewrite, overrides force a version everywhere in the tree, which often breaks a transitive dep that genuinely needed the old version.

When ERESOLVE signals a deeper problem

Recurring ERESOLVE means your dependency graph has incompatible major-version expectations across direct deps. The architectural cause is a fragmented framework ecosystem, typically a UI kit pinned to React 17, a state library tracking React 18, and a router demanding React 19, with no upstream coordinator. Permanent fix is to pick a framework with a curated dep set (Next.js, Remix, Vite + a paired UI kit) and let the meta-framework's peerDependencies act as the version oracle. Without that, every minor UI library upgrade reignites the resolution war.

Editor's take

This one has a particular talent for surfacing at the worst possible moment: a small startup's engineer has just cloned a two-year-old monorepo, it's 45 minutes before a CEO demo, and `npm install` exits with ERESOLVE across three conflicting React version constraints. The project worked fine on the last developer's machine running Node 16 and npm 6. Now it's Node 22, npm 10, and Arborist has decided to actually enforce what the authors always intended. The legacy-peer-deps flag buys you through the demo, but that tech debt just moved onto your backlog permanently.

Hitting this error and actually understanding why it happened — not just cargo-culting `--legacy-peer-deps` into every install — marks a real inflection point. Junior devs add the flag and move on. Mid-level engineers learn to read the conflict tree npm prints and identify which package is the real offender. The senior move is running `npm ls react` to map the full version graph, then deciding whether to pin, patch, or file an upstream issue. Understanding peer dependency semantics is the same mental model you need for Cargo workspaces, Gradle dependency resolution, and Python extras — it generalizes upward.

This error rarely arrives alone. In the same session you'll likely encounter `npm WARN ERESOLVE overriding peer dependency` warnings cascading after the `--legacy-peer-deps` workaround, followed by runtime `Invalid hook call` errors because two separate copies of React ended up in `node_modules`. Downstream you'll often find `ERR_PACKAGE_PATH_NOT_EXPORTED` from ESM/CJS boundary mismatches when transitive deps pull incompatible sub-paths, and `MODULE_NOT_FOUND` for peer packages the resolver silently deduped away. The install succeeded; the runtime didn't.

By Bikram Nath · Curator · Updated April 2026

Frequently asked questions

Is --legacy-peer-deps safe?

For most cases, yes. It mirrors npm 6 behaviour which worked for years. Risk: a true peer-dep incompatibility will manifest as a runtime error instead of an install error.

What's the difference between --force and --legacy-peer-deps?

--force installs everything regardless of conflicts. --legacy-peer-deps only relaxes peer-dep rules. --legacy-peer-deps is safer.

Why does pnpm not have this problem?

pnpm uses a different resolution algorithm and handles peer deps per-package rather than globally.

disclosure:Errordex runs AdSense, has zero third-party affiliate or sponsored links, and occasionally links to the editor’s own paid digital products (clearly labelled). Every fix is cross-referenced against the official sources listed in the “sources” sidebar before it ships. If a fix here didn’t work for you, please email so we can update the page.