/개발/How to Fix npm ERESOLVE unable to resolve dependency tree by Cause
Developmentnpm ERESOLVE unable to resolve dependency treelegacy-peer-deps force 차이

How to Fix npm ERESOLVE unable to resolve dependency tree by Cause

A practical, cause-by-cause guide to the npm ERR! ERESOLVE unable to resolve dependency tree error. Compares --legacy-peer-deps, --force, and overrides, and covers npm ci failures in CI plus resetting package-lock.json.

How to Fix npm ERESOLVE unable to resolve dependency tree by Cause

Fix npm ERESOLVE in 5 Minutes: Cause-by-Cause Fixes for unable to resolve dependency tree

If npm install was working fine yesterday and this morning it suddenly dumped a red error and stopped—and you copied that console output, searched, and landed here—you’re in the right place. This article has one goal: unblock the build in five minutes, then track down the root cause. For anyone in a hurry, here is the fastest temporary escape hatch first.

Bash
# The fastest one-liner to unblock a stuck install
npm install --legacy-peer-deps

If this command gets the build through, take a breath, then read on for why this happens and for cleaner long-term fixes.

That error you saw—it’s one of these, right?

For search accuracy, here is the actual console output. If you’ve seen any of the variants below, this article is exactly for you.

TEXT
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: my-app@1.0.0
npm ERR! Found: react@18.2.0
npm ERR! node_modules/react
npm ERR!   react@"^18.2.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^17.0.0" from some-legacy-lib@2.3.1
npm ERR! node_modules/some-legacy-lib

npm WARN ERESOLVE overriding peer dependency
npm error ERESOLVE could not resolve

The key phrases are ERESOLVE unable to resolve dependency tree, Could not resolve dependency: peer, and overriding peer dependency. The message is in English, which can be intimidating, but once you know the structure you can pinpoint the cause in five seconds.

What ERESOLVE actually is: the peer dependency policy change from npm v7

The root of this error is a policy change in npm. Through npm v6, peer dependency conflicts were simply ignored (auto-flattened): npm printed a warning and continued the install. From npm v7 onward, npm tries to install peer dependencies automatically, and if the dependency tree cannot satisfy everything at once (e.g. A requires react 17 while B requires react 18), it aborts the install entirely (ERESOLVE). With npm v10 as the default today, this strict behavior is the standard, and the error has exploded especially after the React 19 release because older libraries have not yet updated their peer ranges. Reading the log line by line:

  • While resolving: my-app@1.0.0 → which package was being installed when the conflict occurred
  • Found: react@18.2.0 → the version already locked in the current tree
  • Could not resolve dependency: peer react@"^17.0.0" from some-legacy-lib → which package wants what, and failed to match

In other words, the log means: “My project uses react 18, but some-legacy-lib insists on react 17 only.”

Comparison of 4 fix recipes

Pick the prescription that matches your situation. Higher in the table is faster and rougher; lower is slower but more fundamental.

ApproachCommand / configBehaviorSide effectsWhen to use
--legacy-peer-depsnpm install --legacy-peer-depsSkip peer checks the npm v6 wayPotential runtime compatibility riskUrgent build recovery; fine in most cases
--forcenpm install --forceIgnore conflicts and force the installLeaves a broken tree as-isLast resort
overridesJSON config in package.jsonPin a specific nested dependency versionRuntime errors if you pin the wrong versionSurgical fix; recommended for teams
Version alignmentMatch versions yourselfRoot-cause fix that satisfies peer requirementsTakes time; may require code changesPermanent fix

1) --legacy-peer-deps (the most reasonable temporary escape hatch)

Bash
npm install --legacy-peer-deps

If you don’t want to type it every time, put it in .npmrc at the project root.

INI
# .npmrc
legacy-peer-deps=true

2) --force (only when you are truly desperate)

Bash
npm install --force

It carries a broken tree forward, so it can cause nastier runtime bugs. Avoid it unless you are about to demo.

3) package.json overrides (the approach I prefer most)

In practice I prefer pinning just the offending package with overrides rather than ignoring peer checks globally with --legacy-peer-deps. The change lives in code, so teammates can trace what was overridden and how.

JSON
{
  "overrides": {
    "some-legacy-lib": {
      "react": "$react"
    },
    "another-lib": {
      "react-dom": "18.2.0"
    }
  }
}

"$react" means “follow whatever react version the root project uses.” After applying it, re-lock with rm -rf node_modules package-lock.json && npm install.

4) Version alignment (the root-cause fix)

Use a command like npm ls react to see who requires which version, then upgrade or replace the conflicting package with a version that supports the peer. It takes time, but it is the proper way to get a clean lock file.

When npm ci breaks in CI / Docker

The most common case is “works locally, fails only in CI.” Unlike npm install, npm ci requires the lock file and package.json to match 100%, and it fails immediately on mismatch or a peer conflict.

On GitHub Actions there are two approaches.

YAML
# Approach A: pass the flag on the step
- run: npm ci --legacy-peer-deps

# Approach B: commit .npmrc (legacy-peer-deps=true) → the step is just npm ci

Committing .npmrc makes local, CI, and Docker behave the same, which is better for consistency. In a Dockerfile, setting it via an environment variable keeps cache layers intact and stays clean.

Dockerfile
ENV NPM_CONFIG_LEGACY_PEER_DEPS=true
COPY package*.json ./
RUN npm ci
COPY . .

The trap you hit most often is an npm version mismatch between local and CI. If local is npm v9 and CI is v10, resolve results differ and you get the “it worked on my machine” incident. Pin versions with engines in package.json and .nvmrc.

JSON
{ "engines": { "node": ">=20", "npm": ">=10" } }

Procedure to reset a tangled package-lock.json

This is the clean-reset sequence when the lock file is partially corrupted and no command works.

Bash
rm -rf node_modules package-lock.json
npm cache verify
npm install

Resetting the lock is a double-edged sword. Every dependency is re-locked to the latest compatible version, so you can lose reproducibility. If you reset a team-shared lock file alone and commit it, you can break a pile of “it was fine a minute ago” teammate environments—always share the change in a PR and get a review. Also, pnpm and Yarn Berry use a strict peer policy by default, so if you are considering a migration, expect these conflicts more often. In a monorepo (workspaces), check hoisting locations as well.

For reference, the Python world has the same pain. In pip the equivalent dependency conflict shows up as ResolutionImpossible; the philosophy is similar but the tools are completely different (related: pip ResolutionImpossible troubleshooting guide).

Conclusion: a decision checklist by situation

Apply these in urgency order, but do not stay on the workaround—follow the roadmap.

  1. You only need the build unblocked right nownpm install --legacy-peer-deps
  2. You have identified the offending package → pin it with package.json overrides
  3. It only breaks in CI → unify the npm version (engines / .nvmrc) and commit .npmrc
  4. The lock is completely tangled → clean reset (PR required if the team shares it)
  5. You have time → align conflicting package versions for a root-cause fix

--legacy-peer-deps is first aid, not a cure. If a deadline forced you onto a workaround, leave a single “dependency cleanup” ticket in the backlog. It will save you on the next React major upgrade.

References: official docs

The primary sources for the behavior, settings, and errors covered in this article are the following official docs. Check them for version-specific options and exact behavior.

FAQ

Q. What is the difference between --legacy-peer-deps and --force? A. --legacy-peer-deps skips only peer dependency validation and still builds the rest of the tree normally. --force ignores conflicts and forcibly installs even a broken tree, so it is much more dangerous. Use --legacy-peer-deps day to day; save --force for a true last resort.

Q. It works locally, but CI npm ci fails with ERESOLVE. A. Almost always an npm version mismatch between local and CI, or a lock file mismatch. Pin Node/npm with .nvmrc and engines, and commit legacy-peer-deps=true in .npmrc so environments match.

Q. Is it safe at runtime if I force-pin with overrides? A. It is safe when the library actually works with the newer version and only the peer range was never updated. If you force-fit a truly incompatible major difference, you can get runtime errors—always run core feature tests after pinning.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·
관련 공식 문서Node.js 공식 문서

Comments

Be the first to comment.