Diagnosing npm ERESOLVE and lockfile sync failures
Step‑by‑step guide to diagnose npm ERESOLVE errors and lockfile sync failures, with checks, fixes tied to causes, and escalation criteria.
31 Aug 2025, 04:46 UTC

Recognizable condition
When running npm install or npm ci the command aborts with an error like:
npm ERR! code ERESOLVE
npm ERR! Could not resolve dependency
npm ERR! peer react@\"^18\" from package-a@2.0.0 conflicts with package-b@1.5.0 which requires react@\"^17\"
Cause / diagnostic table
| Symptom | Likely cause |
|---|---|
| ERESOLVE with \"Could not resolve dependency\" | Requested root dependency ranges plus transitive peerDependencies have no single satisfying version. |
| npm ci fails with lockfile out of sync | package.json was edited after the lockfile was generated; npm ci expects exact sync. |
| Both errors appear after a version bump | A direct dependency was upgraded, pulling a newer peer range that conflicts with another dependency’s peer requirement. |
Ordered checks
- Read the full error – note the peer package name and the two conflicting ranges (e.g.,
react@\"^18\"vsreact@\"^17\"). Run this in the project root; no special permissions needed. - Identify which dependencies pull each range:
npm ls <peer-package>– shows where the peer appears in the tree and which version is currently resolved.npm explain <dependent-package>– explains why a specific version of<dependent-package>was chosen, listing its peer requirements.
node_modulesandpackage-lock.json. - Confirm toolchain versions:
Record the output; behavior of peer‑dependency resolution differs between npm 7, 8, 9, 10.node -v npm -v - Test lockfile generation:
If this succeeds, a lockfile can be produced; if it fails with ERESOLVE, the conflict is in the dependency tree, not just a stale lockfile.npm install --package-lock-only - Diff root entries:
(Replace the process substitution with a temporary file if your shell doesn’t support it.) This shows which direct dependencies have changed betweengit diff --no-index package.json <(npm ls --json --depth=0 | jq -r '.dependencies | to_entries | map(\"\(.key): \(.value.version)\") | sort[]')package.jsonand the lockfile.
Fixes tied to findings
1. Transitive peer conflict – use overrides
If the conflict originates from a transitive dependency (e.g., package-a requires react@^18 but package-b needs react@^17), add an explicit overrides to force a single version:
# In package.json
\"overrides\": {
\"react\": \"^18\"
}
Run npm install (or npm ci after committing the lockfile) to apply the override. Risk: Overrides affect the whole tree and may silently downgrade/upgrade many transitive packages; always inspect the resulting package-lock.json diff before committing.
Rollback: Remove the overrides entry and run npm install again to revert to the previous resolution.
2. Root range too strict – widen the dependency
If a direct dependency you control declares an overly tight peer range (e.g., \"react\": \"^17\" while the rest of the tree needs ^18), update that dependency’s version in package.json:
npm install react@^18 --save-exact
Then regenerate the lockfile and retry npm ci.
3. Lockfile drift – regenerate and commit
When only CI fails with a lockfile‑out‑of‑sync error, regenerate the lockfile on a clean checkout:
# Local development branch
rm -rf node_modules package-lock.json
npm install # creates a fresh lockfile
# Commit the new lockfile
git add package-lock.json
git commit -m \"chore: update lockfile after dependency changes\"
After pushing, CI will run npm ci against the synchronized lockfile.
Rollback: If the new lockfile introduces problems, reset to the previous commit (git checkout HEAD~1 -- package-lock.json) and reinstall.
Escalation criteria
- The conflict involves a private‑registry package you cannot modify, and
npm explainshows the unsatisfiable range comes from that package with no compatible release. - Two direct dependencies require mutually exclusive major versions of a peer (e.g., one needs
react@^16, another needsreact@^18) and no version satisfies both. - After regenerating and committing the lockfile,
npm cistill fails with ERESOLVE in a clean checkout. - Using
--legacy-peer-depsor--forceunblocks the build but you suspect hidden incompatibilities; prefer a proper fix.
Verification
- Reproduce in a clean clone:
rm -rf node_modules package-lock.json && npm install, then runnpm ciand confirm it completes without ERESOLVE or sync errors. - After applying a fix, run
npm ls <peer-package>andnpm explain <dependent-package>; ensure no \"invalid\" or \"missing\" markers appear for the previously conflicting peer. - Check lockfile stability: run
npm ciin CI (ornpm install --dry-runlocally) and verifygit diff --exit-code package-lock.jsonreturns no changes. - Add
node -v && npm -vto your CI job output so the diagnostic log records the exact toolchain used.
Limitations
overridesapply globally; they may affect packages you did not intend to change. Review the full diff ofpackage-lock.jsonbefore committing.- Widening a root dependency’s range may introduce breaking changes if the package actually requires the older peer version; test your application thoroughly.
- The guidance assumes npm 7 or later (auto‑install of peers). If you are on npm 6, peer dependencies are not installed automatically and the error messages differ.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.