Watch at EaseStories. Answers. Perspective.

Technology · PRACTICAL GUIDE

npm ERESOLVE? Prove the peer-dependency contract before using force

Preserve the lockfile and error graph, identify the demanding peer edge, repair the version-range intersection, then prove a clean install without bypass flags.

Original diagram mapping the root project, requester, peer range and selected package version in an ERESOLVE conflict.
Original illustration: find the exact requester, peer range and selected version before changing the tree. Watch at Ease

ERESOLVE is a dependency-graph verdict, not proof that the cache is broken. The message usually names one selected package version, one requester and one peer range that cannot coexist under the current tree.

Preserve the manifests, lockfile and full report. Reconstruct the demanding edge, repair the smallest version contract, and require a clean npm ci plus tree, build and test evidence before calling the incident resolved.

Freeze the evidence before changing the tree

Save package.json, package-lock.json, workspace manifests, project .npmrc, node --version, npm --version, the complete ERESOLVE report and the exact install command. Do not begin by deleting the lockfile or cache: that destroys the comparison between the previously selected tree and the failing request.

Read the error in order. While resolving names the project or package being processed; Found names the selected version; Could not resolve dependency names the demanding package and its peer range. Copy those four items into a ledger instead of treating ERESOLVE as a generic cache error.

Prove the demanding edge and range intersection

When a tree exists, run npm explain for the selected package and for the requester. npm documents that explain prints the dependency chain that caused a package to be installed and can target an exact node_modules path. Add npm ls and npm view <package>@<version> peerDependencies --json to record the installed edge and the registry contract separately.

Compare the root range, the requester's peer range, the selected version and any override. SemVer describes compatibility intent, but a matching range is not runtime proof. If the intersection is empty, select releases whose declared ranges intersect; if the ranges do intersect, test lockfile drift, workspace/file links, overrides and the exact npm version before blaming the packages.

Repair the contract instead of silencing it

Prefer a compatible package release, coordinated upgrade or documented override that preserves the peer contract. Commit the minimal manifest and lockfile diff together, and explain which dependency edge changed. Avoid upgrading unrelated packages during the same repair because it makes the proof ambiguous.

npm says legacy-peer-deps completely ignores peerDependencies and is not recommended because meta-dependencies may rely on that contract. Treat it only as an isolated diagnostic: if it changes the outcome, you learned that peer enforcement is involved, not that the resulting tree is compatible. Force is broader still and is not an exit criterion.

Separate a real conflict from resolver or lockfile behavior

Reproduce in a clean temporary clone with the same Node, npm, .npmrc and registry. Run the frozen path first. npm ci removes node_modules, refuses a package.json/lockfile mismatch and does not rewrite the lockfile, so its failure is useful evidence rather than a prompt to erase the lock.

If identical declared ranges still fail only on one npm release, reduce the graph and compare adjacent npm versions. The 2025 npm/cli issue 8470 records a reproducible overrides case where ERESOLVE appeared despite matching 1.0.0 peers, so a minimal reproduction can be the correct next step after—not before—the contract ledger proves no empty intersection.

Require a reproducible exit proof

The repair passes only when a fresh checkout completes npm ci without bypass flags, npm explain and npm ls show the intended requester and peer version, the manifest and lockfile diff are understood, and the application build and tests pass. Save those outputs with the Node/npm versions.

If production intentionally keeps legacy-peer-deps, make that an explicit project policy in .npmrc, document the ignored contract and add runtime tests for the affected integration. That is a controlled exception, not a claim that ERESOLVE was false. Revisit it when either peer range or resolver version changes.

Original diagram showing evidence preservation, dependency explanation, version alignment and clean-install validation.
Original illustration: repair the dependency contract, then prove npm ci, the tree, build and tests. Watch at Ease