Skip to content

Fix: Poetry Dependency Conflict (SolverProblemError / No Solution Found)

FixDevs · (Updated: )

Part of:  Python Errors

Quick Answer

How to fix Poetry dependency resolution errors — SolverProblemError when adding packages, conflicting version constraints, how to diagnose dependency trees, and workarounds for incompatible packages.

The Error

Running poetry add some-package or poetry install fails with:

SolverProblemError

Because myproject depends on package-a (^2.0) and package-b (^3.0)
 and package-b (3.0.0) depends on package-a (^1.0),
 package-a cannot be both >=2.0,<3.0 and >=1.0,<2.0.

So, because myproject depends on package-a (^2.0), version solving failed.

Or when adding a new package:

Because requests (2.31.0) depends on urllib3 (<3,>=1.21.1)
 and your project depends on urllib3 (^2.0), requests is forbidden.

Or after pulling a project:

poetry install
...
PackageNotFound: Package pandas (1.5.0) not found.

Why This Happens

Poetry’s resolver is built on Mixology, a port of the Dart language’s pub solver — a backtracking SAT-style algorithm that explores the dependency graph and proves either a satisfying assignment or a conflict explanation. When you see SolverProblemError, the solver has explored the available versions and arrived at a contradiction. The explanation it prints is not just an error message; it is the literal chain of derivations the solver used to prove the conflict. That is why the explanation is sometimes long: it traces upstream packages that you do not directly depend on.

The conflict is usually one of three shapes. Direct constraint contradiction is the obvious case — requests >=2.32 and requests <2.30 in the same project cannot coexist. Transitive contradiction is more common: you do not declare the conflicting package, but two of your dependencies pull in incompatible versions of a shared sub-dependency (often urllib3, pydantic, httpcore, or protobuf). Marker contradiction is the subtle case: a constraint is conditioned on python_version or sys_platform and Poetry must find a version that works across every platform you target.

There is also a class of problems that look like solver issues but are not. A PackageNotFound after poetry install usually means a package version recorded in poetry.lock has been yanked from PyPI — the resolver succeeded once but the world has changed. The Resolving dependencies... step hanging for tens of minutes is usually Poetry probing every version on PyPI for a transitive dependency that has hundreds of releases (the classic example is boto3). Both look like conflicts and neither is really one.

  • Direct conflict — package A requires requests>=2.28 and package B requires requests<2.28. Both cannot be true.
  • Transitive conflict — you don’t directly depend on the conflicting package, but two of your dependencies pull in incompatible versions of a shared sub-dependency.
  • Overly strict constraints — your pyproject.toml pins a version too tightly (e.g., urllib3 = "1.26.0" instead of urllib3 = ">=1.26.0").
  • Python version incompatibility — a package you are trying to install only supports Python 3.10+, but your project targets Python 3.9.
  • Lock file out of sync — the poetry.lock references a package version that no longer exists on PyPI (yanked release).

Version History That Changes the Failure Mode

The Poetry CLI has shipped several behavior changes that affect how conflicts are reported and resolved. Identify your version with poetry --version before applying any fix from older threads:

  • Poetry 1.2 (August 2022) — Introduced the plugin system, dependency groups ([tool.poetry.group.dev.dependencies] replacing [tool.poetry.dev-dependencies]), and the poetry-core build backend split. The solver was rewritten to handle markers more aggressively, which surfaced previously-silent transitive conflicts as new SolverProblemErrors after the upgrade.
  • Poetry 1.3 (December 2022) — Stabilized the new lock format. Removed legacy setup.py-based installs in favor of PEP 517 builds. poetry export was moved into a separate plugin.
  • Poetry 1.4 (February 2023) — Lockfile format v2 became the default. The old v1 format is still readable but new locks are written in v2. Mixed-version teams (one developer on 1.3, another on 1.4) end up rewriting the lock file on every commit, which looks like a phantom conflict.
  • Poetry 1.5 (May 2023) — Added explicit source priorities: default, primary, supplemental, explicit. Replaced the deprecated secondary source mode. If you depend on a private PyPI mirror, you now have to set its priority correctly or Poetry will fall back to public PyPI and produce different solutions.
  • Poetry 1.6 (August 2023) — Added poetry lock --no-update semantics for lockfile-only mode and removed setup.py egg_info shim. Improved error messages for marker conflicts.
  • Poetry 1.7 (November 2023) — Added poetry self add for plugins and reworked the keyring backend selection. Compatibility with pip 23.x’s new resolver was reported as smoother (fewer false-positive solves that fail at install time).
  • Poetry 1.8 (February 2024) — Added the install-completer for fast partial installs, and made poetry lock re-check published packages by default. Means a yanked release is now caught at lock time, not at install time.
  • Poetry 2.0 (December 2024) — Adopted PEP 621 for project metadata. [project] is preferred over [tool.poetry] for the basic fields (name, version, dependencies), though the tool-specific configuration stays under [tool.poetry]. Migration is one-way; once you adopt 2.0 format, older Poetry versions cannot read it.

If you upgraded from 1.4 to 1.5+ and started seeing private-index packages drop out of the lock file, the cause is the new source priority semantics. Re-declare the index with priority = "primary" (or explicit if it should only be used for named packages). The pip 23+ resolver also rejects some packages that older Poetry locks accepted; if pip install -r requirements.txt exported from Poetry fails, regenerate the export with poetry export -f requirements.txt --without-hashes.

Fix 1: Diagnose the Conflict

Before fixing, understand exactly what is conflicting:

# Show the full dependency tree
poetry show --tree

# Show why a specific package is installed and what requires it
poetry show requests
# Output shows: required by, version installed, dependencies

# Check what version constraints are on a package
poetry show --tree | grep -A5 "urllib3"

# See all packages and their versions
poetry show

# Check for outdated packages
poetry show --outdated

Read the error message carefully. Poetry’s error messages are detailed — they tell you exactly which packages conflict and why:

Because httpx (0.24.0) depends on httpcore (>=0.17.0,<0.18.0)
 and aiohttp (3.8.5) depends on httpcore (>=0.16.0,<0.17.0),
 httpx and aiohttp are incompatible.

This tells you httpx and aiohttp cannot coexist in their current versions because they require different httpcore ranges.

Fix 2: Relax Version Constraints

Overly strict pinning in pyproject.toml is the most common fixable cause:

# pyproject.toml — before (too strict)
[tool.poetry.dependencies]
python = "^3.9"
requests = "2.28.0"      # Exact pin — inflexible
urllib3 = "^1.26"        # May conflict with requests' requirements

# After — relaxed constraints
[tool.poetry.dependencies]
python = "^3.9"
requests = "^2.28"       # Allow any 2.28.x or higher (within major)
urllib3 = ">=1.26,<3"    # Allow 1.x or 2.x

Common constraint syntax:

package = "^2.0"    # >=2.0.0, <3.0.0 (caret — most common)
package = "~2.1"    # >=2.1.0, <2.2.0 (tilde — patch-level)
package = ">=2.0"   # Any version 2.0 or higher
package = ">=2.0,<3" # Range
package = "*"       # Any version

After relaxing constraints:

poetry update package-name  # Re-resolve with new constraints

Fix 3: Update the Conflicting Package

Often the conflict is because you are requesting a new package that requires a newer version of a shared dependency than your existing packages allow:

# Update a specific package that is causing the conflict
poetry update urllib3

# Update all packages to their latest compatible versions
poetry update

# Add a package and allow Poetry to upgrade dependencies
poetry add new-package --no-interaction

Check if a newer version of the conflicting package resolves it:

# See available versions of a package
poetry search some-package

# Or check PyPI directly
pip index versions some-package

Fix 4: Use Dependency Groups to Isolate Conflicts

If the conflict is between development and production dependencies, separate them into groups:

# pyproject.toml
[tool.poetry.dependencies]
python = "^3.11"
fastapi = "^0.104"
sqlalchemy = "^2.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.4"
black = "^23.0"
# Dev tools with conflicting deps go here — isolated from production

[tool.poetry.group.test.dependencies]
pytest-asyncio = "^0.21"
httpx = "^0.25"   # May conflict with aiohttp in dev group — separate group isolates it
# Install only production dependencies (no dev groups)
poetry install --only main

# Install with a specific group
poetry install --with test

# Install without a specific group
poetry install --without dev

Fix 5: Override a Transitive Dependency

When two packages require incompatible versions of a shared sub-dependency and you cannot upgrade either package, use overrides to force a specific version:

# pyproject.toml — force a specific version of a transitive dependency
[tool.poetry.dependencies]
python = "^3.11"
package-a = "^2.0"
package-b = "^3.0"

# Force urllib3 to a version compatible with both package-a and package-b
[tool.poetry.dependencies.urllib3]
version = "^1.26"
python = "*"

For more complex overrides — use poetry source or direct path dependencies:

# Pin a transitive dep by adding it directly with a compatible range
[tool.poetry.dependencies]
urllib3 = ">=1.26.0,<3"  # Explicitly manage the transitive dep
poetry lock --no-update  # Re-lock without upgrading other packages
poetry install

Fix 6: Use pip as a Fallback for Truly Incompatible Packages

When Poetry’s solver cannot find a solution but you know the packages actually work together at runtime, install one of them with pip directly inside the virtual environment:

# Activate the Poetry virtual environment
poetry shell

# Install the conflicting package with pip (bypasses Poetry's solver)
pip install some-problematic-package==1.2.3

# Return to normal Poetry workflow for everything else
exit

Warning: Packages installed with pip inside a Poetry environment are not tracked in pyproject.toml or poetry.lock. This is a last resort — document it clearly and investigate a proper fix. The dependency may break on the next poetry install.

Alternative — use a virtual environment directly:

python -m venv .venv
source .venv/bin/activate
pip install package-a package-b  # No solver — just installs

Fix 7: Recreate the Lock File

If poetry.lock is out of sync or corrupted:

# Delete and regenerate the lock file
rm poetry.lock
poetry lock

# Then install
poetry install

If a specific package version was yanked from PyPI:

# Find what version is in the lock file
grep -A5 "name = \"pandas\"" poetry.lock

# Force update to a non-yanked version
poetry add pandas@^2.0  # Specify a valid version range

# Or update just that package
poetry update pandas

Migrate from older Poetry versions (1.x to 1.5+/2.x):

# Poetry 2.x changed pyproject.toml format — update the project
poetry self update

# After updating Poetry, re-lock
rm poetry.lock
poetry lock
poetry install

Still Not Working?

Try --verbose to see the full solver trace:

poetry add some-package -vvv 2>&1 | head -100

Check if the conflict is in dev dependencies only. If production works but dev doesn’t, move the conflicting tool to an isolated group.

Check Python version compatibility. Some packages drop support for older Python versions in their latest releases:

# Require Python 3.11+ if needed packages require it
[tool.poetry.dependencies]
python = "^3.11"
# Check which Python versions a package supports
pip index versions some-package  # Check available versions
pip show some-package            # After install — shows requires-python

Use poetry env info to verify which Python and virtual environment Poetry is using:

poetry env info
# Shows Python version, virtual env path, and active status

poetry env list  # List all environments for this project
poetry env use python3.11  # Switch Python version

Check whether a private index is masking a public version. With Poetry 1.5+‘s source priority system, a primary source overrides PyPI. If your private mirror only carries an older version of a package, the solver will silently pick that older version and report a conflict against the newer constraints. Verify with poetry config repositories and confirm the priority of each source matches what you expect.

Check that poetry lock is not being run on a stale pyproject.toml. A common workflow bug is editing pyproject.toml, running poetry install without re-locking, and watching the install pull the old constraints from the lock. Run poetry lock --no-update after every manual edit to pyproject.toml, then poetry install.

Check the platform markers on transitive deps. Some packages declare python_version or sys_platform markers that cause the solver to require a version that doesn’t exist for your platform. poetry show --tree will show the markers — if a sub-dependency lists (python_version < "3.10") and you target 3.11, the solver may have nothing to install. Bump the minimum Python in pyproject.toml or pick a package that supports your target.

For related Python environment and package issues, see Fix: pip No Matching Distribution Found, Fix: Python ModuleNotFoundError (venv), Fix: pip Externally-Managed-Environment, and Fix: pip Could Not Build Wheels.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles