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.
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: ResolutionImpossibleThe key is the "The conflict is caused by:" block. Unpacking the example above:
- You (
The user requested) explicitly asked forurllib3==2.0.0. - But
botocore(a transitive dependency pulled in by boto3) requiresurllib3<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.
pip install pipdeptree
pipdeptree -p urllib3 --reverse # urllib3를 누가 요구하는지 역추적These tricks are handy for checking which versions are even available.
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.
| Aspect | Old (legacy) | Current (backtracking) |
|---|---|---|
| Conflict checking | Loose; installs the first version it finds | Checks that all constraints can be satisfied at once |
| On conflict | Quietly installs a broken set | Stops with ResolutionImpossible |
| Risk | ImportError blows up at runtime | Blocked 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:
# requirements.txt — before (충돌)
boto3==1.26.76
urllib3==2.0.0 # botocore가 <1.27을 요구 → 충돌# 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
pip install -r requirements.txt --use-deprecated=legacy-resolverIt 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.
(c) Generate a deterministic lock with pip-tools — the recommended workflow
List only your direct dependencies in requirements.in and let the tool lock the rest.
# requirements.in — 내가 진짜 쓰는 것만
boto3
requests
pandaspip 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.
# constraints.txt
urllib3>=1.26,<2python -m venv .venv && source .venv/bin/activate # 가상환경 분리는 필수
pip install -r requirements.txt -c constraints.txtA 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-compileto Git - ✅ Run
pip-compile --upgraderegularly 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.
Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
Comments
Be the first to comment.