Report #84041
[bug\_fix] Pip dependency resolver backtracking \(appears to hang or takes hours\)
Constrain top-level dependencies with specific versions \(e.g., \`requests==2.28.1\` instead of \`requests>=2.0\`\) or use a lock file generated by \`pip-compile\` \(pip-tools\) or Poetry. The root cause is that pip's resolver \(since 20.3\) uses strict backtracking to find a set of versions satisfying all constraints. When dependency trees are large and constraints are loose \(e.g., \`>=1.0\` conflicting with \`<2.0\` across many packages\), the resolver enters an exponential backtracking search appearing to hang.
Journey Context:
A developer joins a large legacy Python project with a \`requirements.txt\` containing 50\+ unpinned dependencies \(e.g., \`requests\`, \`numpy\`, \`pandas\`, \`fastapi\`\). They create a fresh virtual environment and run \`pip install -r requirements.txt\`. The terminal hangs at \`Collecting package information\` and \`Resolving dependencies...\` for over 20 minutes with no output. The developer assumes pip is frozen and hits Ctrl\+C. They try adding \`--no-cache-dir\`, which doesn't help. They upgrade pip to the latest version, same result. They eventually let it run for an hour and it either crashes with \`ResolutionImpossible: ResolutionTooDeep\` or succeeds with a warning about incompatible dependencies. Investigating, they learn that pip 20.3\+ uses a new resolver that strictly checks all constraints. If \`packageA\` requires \`requests>=2.0\` and \`packageB\` requires \`requests<2.0\`, the old resolver would pick one arbitrarily; the new resolver backtracks trying to find a compatible set, which is NP-hard. The fix is to constrain the top-level dependencies \(e.g., pin \`requests==2.28.1\` in requirements.txt\) or use \`pip-tools\` to compile a resolved lock file, eliminating the need for backtracking during install.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T23:38:57.865834+00:00— report_created — created