/개발/How to Fix pip ResolutionImpossible Dependency Conflicts (Step by Step)
Developmentpip 의존성충돌ResolutionImpossible

How to Fix pip ResolutionImpossible Dependency Conflicts (Step by Step)

Decode pip install ResolutionImpossible and conflicting-dependencies errors from the logs, then fix them. Use practical commands—loosening version ranges, legacy-resolver, pip-tools, and constraints.txt—to cleanly resolve dependency conflic

How to Fix pip ResolutionImpossible Dependency Conflicts (Step by Step)

pip ResolutionImpossible / Dependency Conflict Errors: From 5-Minute Diagnosis to a Complete Fix

Why Did a pip install That Worked Yesterday Suddenly Hit a Red Wall?

Ever set up a new project or cloned a colleague's repo, run pip install -r requirements.txt, and watched the terminal stall before dumping ResolutionImpossible in red? It's jarring when a command that worked just yesterday suddenly hits a wall.

Spoiler: this isn't a bug. pip is doing its job by blocking a combination that should never be installed. By the end of this post you'll be able to pinpoint what's conflicting with what from the red logs in about five minutes, and pick the right fix—from a temporary workaround to a lasting solution. We'll stick to commands you can copy-paste and run.

Decoding the Error: How to Read the Red Log Line by Line

A typical error log looks like this.

CODE
ERROR: Cannot install -r requirements.txt (line 2) and urllib3==2.0.0
because these package versions have conflicting dependencies.

The conflict is caused by:
    The user requested urllib3==2.0.0
    botocore 1.29.76 depends on urllib3<1.27 and >=1.25.4

To fix this you could try to:
1. loosen the range of package versions you've specified
2. remove package versions to allow pip to attempt to solve the dependency conflict

ERROR: ResolutionImpossible

The key is the "The conflict is caused by:" block. Unpacking the example above:

  • You (The user requested) explicitly asked for urllib3==2.0.0.
  • But botocore (a transitive dependency pulled in by boto3) requires urllib3<1.27.
  • 2.0.0 and <1.27 cannot both be true → hence impossible.

The key concept here is transitive dependencies. Packages you never listed yourself—like boto3 → botocore → urllib3—can demand incompatible versions and cause a conflict. Use pipdeptree to see who requires which version.

Bash
pip install pipdeptree
pipdeptree -p urllib3 --reverse   # urllib3를 누가 요구하는지 역추적

These tricks are handy for checking which versions are even available.

Bash
pip index versions urllib3        # 배포된 모든 버전 나열
pip install "urllib3=="           # == 뒤를 비우면 가능 버전 목록을 에러로 출력

Why Is This Failing Now? Meet pip's New Resolver (20.3+)

Here's the answer to "it used to work—why not now?" Starting with pip 20.3, the dependency resolution engine was completely replaced.

AspectOld (legacy)Current (backtracking)
Conflict checkingLoose; installs the first version it findsChecks that all constraints can be satisfied at once
On conflictQuietly installs a broken setStops with ResolutionImpossible
RiskImportError blows up at runtimeBlocked at install time

The old resolver would just install whatever version of a package like urllib3 it happened to pick, and you'd get mysterious errors at import or runtime. Today's backtracking resolver walks possible combinations (backtracks) and stops if none work. The red error is actually catching a latent bug before it ships.

Four Situation-Specific Fix Strategies

(a) Loosen version ranges — the most common, cleanest fix

The cause is often an overly tight pin. Compare before and after:

TEXT
# requirements.txt — before (충돌)
boto3==1.26.76
urllib3==2.0.0      # botocore가 <1.27을 요구 → 충돌
TEXT
# requirements.txt — after (해결)
boto3==1.26.76
urllib3>=1.26,<3    # botocore와 공존 가능한 범위로 완화

Instead of pinning a single version, give a range so the resolver can find a point that satisfies both sides.

(b) --use-deprecated=legacy-resolver — only in a pinch, and know the risk

Bash
pip install -r requirements.txt --use-deprecated=legacy-resolver

It will install. But you've ignored the conflict, so things can still break at runtime. This is an emergency-only way to get a build pipeline unblocked—not a real fix. The legacy resolver is slated for removal, so don't depend on it.

List only your direct dependencies in requirements.in and let the tool lock the rest.

TEXT
# requirements.in — 내가 진짜 쓰는 것만
boto3
requests
pandas
Bash
pip install pip-tools
pip-compile requirements.in        # 전이 의존성까지 해결해 requirements.txt 생성
pip-compile --generate-hashes requirements.in   # 해시 포함(보안·재현성)
pip-sync requirements.txt          # 환경을 lock과 정확히 일치시킴

The generated requirements.txt pins exact versions like urllib3==1.26.18 plus hashes, so everyone on the team gets the same environment.

(d) Pin only transitive deps with constraints.txt

Leave requirements as-is and constrain only the troublesome transitive versions.

TEXT
# constraints.txt
urllib3>=1.26,<2
Bash
python -m venv .venv && source .venv/bin/activate   # 가상환경 분리는 필수
pip install -r requirements.txt -c constraints.txt

A constraints file doesn't say "install this"—it says "if you install it, stay in this range." Combined with a per-project virtualenv, it also keeps you from polluting the global environment.

A Practical Note: Move Where You Pin

Teams that get paged at 2 a.m. over dependency conflicts share one habit: they pin every version by hand. A 100-line requirements.txt full of ==, and every package bump becomes a conflict puzzle. The moment you move pinning from people to pip-compile, conflict-debug time drops by more than half in practice. Humans declare "what we need" in requirements.in; the tool figures out "which version combo actually works."

These days Astral's uv is catching on fast: a Rust-based resolver that's tens of times faster than pip, with clearer conflict messages (uv pip compile can replace pip-tools). Poetry and PDM ship their own lock files and SAT-based solvers, and lock-file standardization (PEP 665 and friends) is still in progress. Whatever tool you use, the "how to read the error log" skill above still applies.

Recurrence-Prevention Checklist

  • ✅ Put only direct dependencies in requirements.in (don't touch transitives)
  • ✅ Prefer ranges (>=,<) for direct deps so the resolver has room to work
  • Commit the lock file produced by pip-compile to Git
  • ✅ Run pip-compile --upgrade regularly to pick up security patches
  • Isolate a virtualenv per project (venv/uv/conda)

References: Official Docs

The primary source for the behavior, settings, and errors covered here is the official documentation below. Check it for version-specific options and exact semantics.

FAQ

Q. I installed with --use-deprecated=legacy-resolver. Can I just leave it? A. Not recommended. You installed while ignoring the conflict, so you can still blow up at import or runtime with AttributeError/ImportError. Unblock the urgent deploy, then immediately loosen ranges or switch to pip-tools for a real fix. The legacy resolver will be removed.

Q. The "The conflict is caused by:" block is too long to read. A. Look at the first line (The user requested) and the range the conflicting package requires. If it's still messy, pipdeptree -p <package> --reverse reverse-traces who pulls that package in—the culprit jumps out.

Q. Can I just switch to uv instead of pip? A. Yes. uv pip install and uv pip compile are largely compatible with the old commands, much faster, and friendlier on conflict messages. Still, get team buy-in first so everyone manages lock files the same way.

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

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

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

Comments

Be the first to comment.