npm ERR! ERESOLVE: Unable to Resolve Dependency Tree

ERESOLVE unable to resolve dependency tree is npm's resolver verdict, not the package you should change. In the current failing resolver run, read the first actionable conflict block: identify the package/version npm is trying to place, the package declaring the incompatible peer range, and that exact range. Also capture the npm version and effective install configuration, because peer-resolution behavior can differ across npm majors/configuration. Repair the dependency contract first; do not default to --legacy-peer-deps or --force.

Node.js · npm · ERESOLVEpeerDependencies · dependency treeLast reviewed Sep 27, 2026
🎯 You’re likely in the right place if:
npm install ends with npm ERR! code ERESOLVE.The report contains Found:, Could not resolve dependency:, and a peer ... from ... line.npm suggests fixing the upstream dependency conflict, retrying with --force, or using --legacy-peer-deps.
Classify the first conflicting package pair
Root project pins a host version outside the peer range →Choose a host version and plugin/library version whose declared ranges overlap.Plugin/framework upgrade changed its peer requirement →Check the release's declared compatibility before upgrading/downgrading either side.The conflicting package is transitive →Use npm explain to find why it exists before adding another direct dependency.package.json and lockfile tell different stories →Determine whether the lockfile is stale or the manifest change is unintended before regenerating it.--legacy-peer-deps or --force makes install pass →Treat that as evidence, not proof that the dependency contract is valid.The conflict block is buried or confusing →Capture the first Found / Could not resolve / peer trio and inspect those package relationships.
Difficulty: ModerateRisk: Low if versions are deliberate
🔎 Quick Check — reduce ERESOLVE to two packages and one range

Start at the first conflict block, not the final npm suggestion. Translate it into: “Project has A@version; B@version requires peer A@range.”

Found: host@3.0.0 Could not resolve dependency: peer host@"^2.0.0" from plugin@5.0.0 Translation: project has host 3.x plugin 5 expects host 2.x

Verify: Before changing anything, you can name the host package, installed/requested version, dependent package, and required peer range.

Did you isolate the conflicting pair?
ADSENSE · reserved slot after the first useful step

Why npm stops here

peerDependencies express a compatibility relationship with a host package. npm's package.json documentation notes that peer dependencies are installed by default from npm v7 onward and conflicting requirements can prevent npm from resolving a valid tree. The useful question is therefore not “How do I bypass ERESOLVE?” but “Which declared compatibility ranges cannot coexist under the npm version, workspace scope and effective resolver configuration actually running this install?”

1
Found
Which version of the host/package is npm trying to place?
2
Peer requirement
Which dependent package declares what semver range?
3
Owner
Is each side direct, framework-managed, workspace-local, or transitive?

Fix #2 — root package version is outside the peer range

If your project directly declares both sides, find a version relationship the package authors actually declare as compatible. For example, if a plugin declares peerDependencies: {"host":"^2"}, installing host 3 does not satisfy that contract merely because both packages install individually.

Check the plugin/library release notes and package metadata before choosing which side to move. Read semver ranges precisely: ^2.3.0 generally permits compatible releases below 3.0.0, but caret ranges below 1.0.0 are intentionally narrower—for example ^0.2.3 does not mean “any 0.x”. Pre-release versions also have special matching rules. When in doubt, evaluate the exact range printed by npm rather than translating every caret to “same major”.

A newer plugin may support the host version you need; alternatively your project may intentionally need the older host until its ecosystem catches up.

Verify: Run the install normally—without bypass flags—then inspect the pair with npm ls host plugin. npm should no longer report that relationship as invalid. Run the relevant build/test afterward.

Fix #3 — an upgrade changed the peer contract

If ERESOLVE appeared immediately after upgrading a framework, plugin or tool, compare the old and new package's peer ranges. Do not assume “latest + latest” is always a compatible pair: release timing and major-version support can differ across packages.

If you choose an older version, make it a deliberate compatibility pin. Check release notes, security advisories, API changes and transitive dependencies. Prefer a maintained release that supports the host version you actually need.

Verify: The chosen versions have overlapping declared compatibility, normal npm install succeeds, and the feature/build that uses the plugin still passes.

Fix #4 — transitive, workspace or monorepo conflict: find who owns the edge

Do not immediately add the transitive package to your root package.json. In npm workspaces/monorepos, first identify which workspace declares the host, which workspace/plugin declares the peer, and whether the install is being resolved from the workspace root. A conflict surfaced at the root can still belong to one workspace's dependency contract.

If the package is already installed, npm explain <package> shows chains that caused that installed package to be present; npm ls <package> --all shows installed versions and invalid/missing relationships. With workspaces, scope your inspection to the relevant workspace when useful instead of assuming the root tree tells the whole ownership story.

npm explain package-name npm ls package-name --all

npm explain explains the installed tree; it is not a reconstruction of the resolver's failed hypothetical tree. If install fails before a usable tree exists—or node_modules reflects an older install—its output may be absent or describe stale state. In that case rely on the current ERESOLVE conflict block plus the relevant workspace/root manifests and lockfile, then inspect the dependency that owns the incompatible range.

Verify: You can identify the direct/workspace dependency that introduces the conflicting package, then fix that owner's version relationship rather than masking it at the root.

Fix #5 — package.json vs package-lock.json: do not delete the lockfile reflexively

The lockfile records npm's resolved dependency graph and metadata for reproducible installs. If package.json changed, first decide whether the new manifest requirement is intentional. Compare the relevant dependency entries and your version-control diff before deleting or regenerating anything. Also distinguish npm install from npm ci: npm ci requires an existing lockfile and exits instead of rewriting it when the lockfile and manifest are out of sync.

Deleting package-lock.json is not a peer-dependency fix. A fresh resolution can change many transitive versions and may still hit the same incompatible peer ranges. Regenerate the lockfile only when you intentionally want a new resolution and can review/test the resulting diff.

Verify: commit/review the manifest and lockfile together. Reproduce the workflow your project actually depends on—often npm ci in CI—using the intended Node/npm version, workspace scope and project resolver configuration. npm documents that if a lockfile was created with flags that materially shape the dependency tree, such as --legacy-peer-deps or --install-links, npm ci needs equivalent configuration; committing the relevant project .npmrc can make that policy reproducible. A local npm install that silently rewrites the lockfile is not enough evidence for a CI fix.

Fix #6 — why --legacy-peer-deps and --force are not the default fix

npm documents legacy-peer-deps as completely ignoring peerDependencies while building the package tree, and explicitly says its use is not recommended because it does not enforce the peer-dependency contract. That can be useful as a temporary diagnostic or migration escape hatch, but a successful install does not prove the packages actually work together.

--force also removes npm protections and should not replace understanding the conflict. Likewise, check whether legacy-peer-deps, strict-peer-deps, workspace selection, or related install settings are already coming from CLI flags, environment or .npmrc; otherwise two developers can appear to run “npm install” while invoking different resolver policy. If a controlled environment temporarily requires a bypass, record that unresolved contract and test the affected integration explicitly.

Good diagnostic signal: if normal install fails but a bypass installs, you have learned that dependency resolution policy is blocking the tree. You have not established compatibility.

Verify: the intended durable policy is explicit and reproducible. Prefer a normal install without a peer-contract bypass; confirm npm ls does not report the target relationship invalid and run build/tests covering the integration. If a temporary migration policy intentionally uses a bypass, do not call the peer conflict resolved—record the policy and remaining compatibility debt.

What about package.json overrides?

npm overrides can be appropriate when the root project intentionally needs to replace a dependency deeper in the tree—for example to use a known-fixed transitive release, keep one dependency version consistent, or replace a package with a fork. npm applies overrides from the root package.json.

An override changes resolution; it does not rewrite another package's compatibility claim into truth. If package B declares a peer range that excludes host A, forcing some transitive version with overrides does not by itself prove B supports A. Use an override only when you understand the dependency edge, the selected replacement is actually compatible, and tests cover the affected behavior.

Also note npm's restriction on overriding a package you directly depend on: the override must match the direct dependency spec unless you reference that direct spec using npm's supported $name form. If your real problem is two direct packages with incompatible peer contracts, align those direct versions instead of using overrides as camouflage.

Verify an override: inspect the resulting tree with npm ls/npm explain, review the lockfile diff, run a clean npm ci where applicable, and run tests that exercise the dependency you replaced.

What not to do

Do not start with --legacy-peer-deps or --force; read the first conflicting peer relationship first.Do not blindly install “latest” versions on both sides and assume their peer ranges overlap.Do not add a transitive package to root dependencies until you know who owns it and why.Do not use overrides merely to make an incompatible peer warning disappear; prove the replacement is compatible and test it.Do not delete package-lock.json as a ritual fix without reviewing the manifest and resulting dependency diff.Do not downgrade to an unmaintained/vulnerable release solely because installation succeeds.Do not stop verification at “npm install returned exit code 0”; inspect the tree and run the affected build/tests.Do not compare local and CI resolution without comparing npm version, workspace scope and effective .npmrc/CLI resolver settings.Do not assume a lockfile generated under legacy-peer-deps or another tree-shaping flag will reproduce under npm ci without equivalent committed configuration.Do not mix an ERESOLVE report from one resolver run with npm explain/npm ls output from a stale node_modules tree and call them the same dependency graph.Do not keep diagnosing the original peer pair after normal resolution succeeds and the failure moves to scripts, build, runtime or another package.

Still seeing ERESOLVE?

Capture the first actionable conflict from the current failing resolver run. Later conflicts may be downstream effects, and fixing the first pair can reveal a new next conflict. If npm wrote an ERESOLVE report, use it as evidence, but correlate it with the command/version/configuration that produced it rather than mixing it with an older node_modules tree or another install attempt.

Before escalating, capture:Node and npm versions plus the exact install command, workspace scope and effective resolver-related .npmrc/CLI settingsthe first Found / Could not resolve dependency / peer blockthe relevant root/workspace package.json dependency and peerDependency entrieswhether each package is direct, workspace, framework-managed or transitivethe relevant package-lock diff or recent dependency change, including whether the lockfile was generated with tree-shaping install flags/configoutput of npm ls for the pair if an installed tree existswhich build/test fails or succeeds after resolution

Official references

Still stuck? Ask the community

Share the first conflict block, package pair/ranges, Node/npm versions, and the dependency change that triggered it. Avoid posting the entire noisy log if the first conflict is enough.

Keep it safe: redact private registry URLs, auth tokens, private package names when confidential, and credentials from npm configuration/logs.
Powered by GitHub DiscussionsSign in with GitHub to comment. Reading comments does not require sign-in.

Loading community discussion…