npm ERESOLVE unable to resolve dependency tree (tested)
ERESOLVE unable to resolve dependency tree is npm's install-time error for a peer dependency conflict: two packages in your tree want incompatible versions of the same dependency. We built a real conflict (react-dom@16 wanting react@16, next to react@19 in the same project), ran a plain install, then measured what --legacy-peer-deps, --force, and the overrides field each actually do.
1. What ERESOLVE means
Since npm 7, npm install checks peer dependencies strictly. If package A requires react@^16 as a peer and your project (or another dependency) installs react@19, npm cannot build one dependency tree that satisfies both. It stops and prints ERESOLVE unable to resolve dependency tree instead of guessing. Per npm's own docs, npm 6 and earlier only warned about this and installed anyway; we did not have npm 6 on this box to confirm that directly.
This is the generic form of a family of peer-dependency conflicts: the same error appears for Angular, ESLint plugins, Babel presets, or any package tree with peer version ranges that don't overlap.
2. Our test setup
We created a throwaway project with two real npm packages whose peer requirements genuinely conflict:
{
"dependencies": {
"react": "19.3.0",
"react-dom": "16.14.0"
}
}
react-dom@16.14.0 declares "peerDependencies": { "react": "^16.14.0" }. We asked for react@19.3.0 directly. Those ranges don't overlap, so this is a genuine conflict, not a contrived one.
3. The exact error
Running npm install with nothing else in the project printed this and exited non-zero:
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@19.3.0
npm error node_modules/react
npm error react@"19.3.0" from the root project
npm error
npm error Could not resolve dependency:
npm error peer react@"^16.14.0" from react-dom@16.14.0
npm error node_modules/react-dom
npm error react-dom@"16.14.0" 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.
No node_modules was created at all. Running npm ls at that point reports both packages as unmet, read straight from package.json:
eresolve-repro@1.0.0 /tmp/npm-eresolve-guide
├── UNMET DEPENDENCY react-dom@16.14.0
└── UNMET DEPENDENCY react@19.3.0
4. Does --legacy-peer-deps work?
Yes, and silently. npm install --legacy-peer-deps printed no warning at all:
added 8 packages, and audited 9 packages in 974ms
found 0 vulnerabilities
Afterward npm ls showed a normal-looking tree:
eresolve-repro@1.0.0
├── react-dom@16.14.0
└── react@19.3.0
This flag makes npm skip peer dependency checks the way npm 6 did. It does not change which versions get installed here; it only stops npm from refusing. It does not check compatibility at all, so a silent install is not proof the combination works at runtime.
5. Does --force work, and how is it different?
Also yes, but noisily. npm install --force printed the conflict as a warning instead of an error, then installed anyway:
npm warn using --force Recommended protections disabled.
npm warn ERESOLVE overriding peer dependency
npm warn While resolving: react-dom@16.14.0
npm warn Found: react@19.3.0
npm warn node_modules/react
npm warn react@"19.3.0" from the root project
npm warn
npm warn Could not resolve dependency:
npm warn peer react@"^16.14.0" from react-dom@16.14.0
npm warn node_modules/react-dom
npm warn react-dom@"16.14.0" from the root project
npm warn
npm warn Conflicting peer dependency: react@16.14.0
added 8 packages, and audited 9 packages in 866ms
found 0 vulnerabilities
The resulting npm ls tree was identical to the --legacy-peer-deps case in this project: react@19.3.0 and react-dom@16.14.0, nothing nested or duplicated. The practical difference we measured is visibility: --force tells you exactly which peer conflict it overrode; --legacy-peer-deps says nothing. --force also re-downloads and re-verifies packages it would otherwise skip, so on a populated cache it can be slower; on this conflict with an empty cache both took under a second longer either way.
6. The modern fix: overrides
npm's overrides field in package.json lets you pin what version a nested or peer dependency resolves to, project-wide. We added this and nothing else:
{
"dependencies": {
"react": "19.3.0",
"react-dom": "16.14.0"
},
"overrides": {
"react-dom": {
"react": "19.3.0"
}
}
}
With that in place, a plain npm install (no flags) succeeded with no warning at all:
added 8 packages, and audited 9 packages in 714ms
found 0 vulnerabilities
npm ls then marked the override explicitly:
eresolve-repro@1.0.0
├── react-dom@16.14.0
└── react@19.3.0 overridden
This is the more deliberate fix: it's visible in version control, scoped to the one dependency that needed it, and doesn't quietly disable peer checks for the rest of the project the way --legacy-peer-deps does. Like the flags above, it only changes what npm resolves; it does not verify that react-dom@16's code actually runs correctly against react@19 at runtime. That's a separate compatibility question npm cannot check for you.
7. Peer-dependency conflicts as a sub-topic
ERESOLVE is just how npm reports a peer dependency conflict at install time. The pattern is always the same shape: package X peer-depends on a range of package Y, something else in your tree wants a different Y, and the ranges don't intersect. Common real-world triggers we've seen described in the same shape as our test:
- Upgrading a framework (React, Angular, Vue) before an ecosystem plugin has published a release that widens its peer range.
- A testing or UI library pinned to an old major version of its host framework.
- Two unrelated packages that each peer-depend on different, non-overlapping ranges of a shared utility like TypeScript or ESLint.
In all of these the fixes are the same three options measured above, in order of preference: upgrade the conflicting package if a compatible release exists, add a scoped overrides entry, or fall back to --legacy-peer-deps/--force only once you've checked the actual code paths involved still work.
8. How to fix it, in order
- Read the error. It names the exact two packages and the exact two version requirements in conflict (section 3).
- Check if either package has a newer release with a wider peer range.
npm view <pkg> peerDependenciesshows the current range without installing anything. - If no upgrade exists, add a targeted
overridesentry (section 6) so only that one resolution is forced, and test the app. - Only use
--legacy-peer-depsor--forceas a last resort, and re-run your test suite afterward — npm installed our conflicting react/react-dom pair without complaint either way; it never checked whether they actually work together. - Run
npm ls <package>afterward to confirm which version actually landed and whether npm flagged it asoverriddenordeduped.
Frequently asked questions
What does ERESOLVE unable to resolve dependency tree mean?
npm found two packages in your project that need incompatible versions of the same dependency and refuses to guess which one you want. We measured this with react@19.3.0 installed next to react-dom@16.14.0, which requires react@^16.14.0 as a peer.
Does npm install --legacy-peer-deps actually fix the conflict?
It makes npm skip peer dependency checks entirely, the way npm 6 behaved. In our test it installed both conflicting packages with no warning at all. It doesn't resolve the conflict or verify the packages work together; it just stops checking.
What's the difference between --force and --legacy-peer-deps?
In our test both produced the same installed tree, but --force printed the exact conflicting versions as a warning ('npm warn ERESOLVE overriding peer dependency') while --legacy-peer-deps printed nothing. --force is the more visible, more honest-about-what-happened option of the two.
Is the package.json overrides field better than --force?
For a known, specific conflict, yes. Adding an overrides entry for just the one dependency let a plain npm install succeed with no flags and no warnings, and npm ls marked the forced version as 'overridden' so it stays visible in the tree. --force and --legacy-peer-deps apply blanket exceptions to the whole install instead.
Will npm warn me if the forced versions don't actually work together?
No. In all three cases we tested (--legacy-peer-deps, --force, overrides) npm only resolves version numbers; it does not run any code. A successful install is not proof react-dom@16 works correctly with react@19 — you still need to test the app.
Written with AI assistance. Measured on 2026-10-02 with npm 11.19.0 and Node.js 24.21.0, installing react@19.3.0 alongside react-dom@16.14.0 (which peer-depends on react@^16.14.0) from the public npm registry. Claims about npm 6's non-strict peer behaviour are per npm's own release notes, not measured here (only npm 11 was available on this box). PlainHeaders is our browser extension; npm and Node.js are free.