What's Actually Happening

You're trying to add a new dependency or update existing packages in your Poetry-managed Python project, but the lock file resolution fails with version conflict errors. Multiple packages require different versions of the same dependency, and Poetry cannot find a compatible resolution.

The Error You'll See

Poetry lock fails with conflicts:

```bash $ poetry add requests>=2.28.0

Updating dependencies Resolving dependencies...

SolverProblemError

Because no versions of requests match >=2.28.0,<3.0.0 and requests (2.28.0) depends on urllib3 (>=1.21.1,<1.27), requests (>=2.28.0) requires urllib3 (>=1.21.1,<1.27).

Because myproject depends on urllib3 (>=2.0.0) and requests (>=2.28.0) requires urllib3 (>=1.21.1,<1.27), version solving failed. ```

Lock resolution timeout:

```bash $ poetry lock

Resolving dependencies... ConnectionError

Could not resolve dependencies. Resolution took too long.

Potential causes: - The dependency graph is too complex - Version constraints are too restrictive - Network connectivity issues ```

Hash mismatch error:

```bash $ poetry install

RuntimeError

The lock file is not up to date with the pyproject.toml. Please run poetry lock to update the lock file.

Hash mismatch: Expected: abc123... Actual: def456... ```

Why This Happens

  1. 1.Version constraint conflicts - Multiple packages require incompatible versions
  2. 2.Circular dependencies - Package A depends on B which depends on A
  3. 3.Overly strict constraints - Exact version pins create conflicts
  4. 4.Outdated lock file - pyproject.toml changes not synced to lock
  5. 5.PyPI package conflicts - Different packages claiming same namespace
  6. 6.Platform-specific deps - Wheels not available for your platform
  7. 7.Private package conflicts - Custom packages with wrong metadata
  8. 8.Dependency removed - Package no longer exists on PyPI

Step 1: Understand Current Dependency State

```bash # Check current dependencies: poetry show

# Show dependency tree: poetry show --tree

# Example output: # myproject 1.0.0 # ├── requests 2.28.0 # │ ├── urllib3 >=1.21.1,<1.27 # │ ├── certifi >=2017.4.17 # │ └── charset-normalizer >=2.0,<3.0 # └── urllib3 2.0.0 (conflict!)

# Check specific package: poetry show requests

# Show all versions of a package: poetry search urllib3

# Check why a package is installed: poetry show urllib3 --why

# View pyproject.toml: cat pyproject.toml

# Example: [tool.poetry.dependencies] python = "^3.10" requests = ">=2.28.0" urllib3 = ">=2.0.0" # Conflicts with requests!

# View lock file status: poetry lock --check

# Check for outdated packages: poetry show --outdated ```

Step 2: Identify the Conflict Source

```bash # Run verbose lock to see resolution process: poetry lock -vvv

# Output shows each step: # • Checking requests (2.28.0) # • Requires urllib3 >=1.21.1,<1.27 # • Conflicts with urllib3 2.0.0 in pyproject.toml # • Trying requests 2.31.0... # • Requires urllib3 >=1.26.0,<2.1.0 # • Compatible with urllib3 2.0.0!

# Use debug mode: poetry lock --debug

# Check specific constraint: poetry show urllib3 # Output: # name : urllib3 # version : 2.0.0 # description : HTTP library with thread-safe... # required : >=2.0.0 (from pyproject.toml) # dependencies : # - requests requires <1.27 (conflict!)

# Find which package requires conflicting version: pip show requests | grep Requires # Requires: urllib3>=1.21.1,<1.27

# Check package metadata on PyPI: curl -s https://pypi.org/pypi/requests/json | jq '.info.requires_dist'

# Check dependency requirements in lock file: grep -A 20 'name = "requests"' poetry.lock ```

Step 3: Relax Version Constraints

```bash # Edit pyproject.toml to relax constraints: # Before: [tool.poetry.dependencies] python = "^3.10" requests = "==2.28.0" # Too strict! urllib3 = "==2.0.0" # Too strict!

# After (use caret or tilde): [tool.poetry.dependencies] python = "^3.10" requests = "^2.28" # Allows 2.28.x, 2.29.x, etc. urllib3 = "^2.0" # Allows 2.0.x, 2.1.x, etc.

# Or use range: requests = ">=2.28,<3.0" urllib3 = ">=1.26,<3.0" # Compatible with requests

# For removing urllib3 (let requests manage it): [tool.poetry.dependencies] python = "^3.10" requests = "^2.28" # Remove urllib3 line - requests will bring compatible version

# Update lock after editing: poetry lock

# Or use add with version update: poetry add requests@^2.31 --allow-prereleases

# For specific compatible versions: poetry add requests==2.31.0 urllib3==2.0.0 # Check if they're compatible first ```

Step 4: Use Poetry's Conflict Resolution Commands

```bash # Clear cache before resolving: poetry cache clear pypi --all

# Try lock with different strategies: poetry lock --no-update # Don't update existing packages poetry lock --no-cache # Bypass cache entirely

# For persistent conflicts, use: poetry lock --no-update --no-cache

# Regenerate lock file completely: rm poetry.lock poetry lock

# Or use Python's built-in solver: poetry config solver.use-poetry-solver false poetry lock

# Try legacy installer: poetry config installer.modern-installation false poetry install

# Use experimental parallel install: poetry config installer.max-workers 4 poetry install

# Check configuration: poetry config --list ```

Step 5: Handle Circular Dependencies

```bash # Identify circular dependencies: poetry show --tree | grep -E "(^\S|├──|└──)" | sort | uniq -d

# If circular found, break the cycle: # Example: package-a -> package-b -> package-a

# Option 1: Remove one dependency: poetry remove package-b

# Option 2: Use extras to make optional: [tool.poetry.dependencies] package-a = {version = "^1.0", extras = ["full"]} package-b = {version = "^1.0", optional = true}

[tool.poetry.extras] full = ["package-b"]

# Option 3: Use dev dependencies: [tool.poetry.group.dev.dependencies] package-b = "^1.0"

# Verify tree after changes: poetry show --tree

# Lock after resolving circular: poetry lock

# Check for remaining cycles: poetry show --tree 2>&1 | head -50 ```

Step 6: Update Specific Packages to Resolve Conflict

```bash # Update requests to version that supports urllib3 2.0: poetry add requests@^2.31.0

# requests 2.31.0 requires urllib3 >=1.26.0,<3.0.0 # Compatible with urllib3 2.0.0!

# Or update all packages: poetry update

# Update specific package: poetry update requests

# Update with latest version: poetry add requests@latest

# Pin to compatible versions manually: # 1. Check compatibility matrix: pip index versions requests pip index versions urllib3

# 2. Find compatible pair: # requests 2.31.0 works with urllib3 1.26.0-2.1.0 # requests 2.32.0 works with urllib3 2.0+

# 3. Add compatible versions: poetry add requests==2.32.0 urllib3==2.0.0

# Verify resolution: poetry show requests urllib3 ```

Step 7: Handle Platform-Specific Dependencies

```bash # Check platform markers in lock file: grep -A 5 'markers = ' poetry.lock

# Example platform-specific deps: [tool.poetry.dependencies] pywin32 = {version = "^300", markers = "sys_platform == 'win32'"} pyobjc = {version = "^9.0", markers = "sys_platform == 'darwin'"}

# For wheels not available: poetry config installer.no-binary :all: poetry install

# Or for specific package: poetry config installer.no-binary numpy poetry add numpy

# Check available wheels: curl -s https://pypi.org/pypi/numpy/json | jq '.urls[].filename'

# For source install when wheels missing: pip install --no-binary :all: numpy

# Use system Python packages: poetry config virtualenvs.options.system-site-packages true poetry env use system

# Check current environment: poetry env info ```

Step 8: Manage Private Package Conflicts

```bash # Add private repository: poetry source add --priority=primary myrepo https://my.pypi.org/simple/

# Configure credentials: poetry config http-basic.myrepo username password

# Or use token: poetry config pypi-token.myrepo my-token-value

# Add package from private repo: poetry add --source myrepo private-package

# Check sources: poetry source show

# For conflicting package names: # Use explicit source in pyproject.toml: [tool.poetry.dependencies] private-package = {version = "^1.0", source = "myrepo"}

# Remove duplicate from PyPI if exists: poetry remove public-same-name-package

# Clear private repo cache: poetry cache clear myrepo --all

# Regenerate lock: poetry lock ```

Step 9: Fix Hash Mismatch and Sync Lock File

```bash # Check if lock file matches pyproject.toml: poetry lock --check

# If mismatch, regenerate: poetry lock

# For persistent mismatch: # 1. Remove lock file: rm poetry.lock

# 2. Remove .toml hash: sed -i '/^content-hash/d' pyproject.toml

# 3. Generate fresh lock: poetry lock

# 4. Verify hash: poetry lock --check # Output: Lock file is valid

# For corrupted lock file: # 1. Backup: cp poetry.lock poetry.lock.bak

# 2. Remove: rm poetry.lock

# 3. Regenerate: poetry lock

# 4. Compare differences: diff poetry.lock poetry.lock.bak

# Validate lock file format: python -c "import tomllib; tomllib.load(open('poetry.lock', 'rb'))" ```

Step 10: Implement Proper Dependency Management Workflow

```bash # Create standardized workflow script: cat << 'EOF' > scripts/poetry-resolve.sh #!/bin/bash

echo "=== Poetry Conflict Resolution ==="

# 1. Clear caches echo "Clearing caches..." poetry cache clear pypi --all 2>/dev/null || true

# 2. Check current state echo "Checking dependencies..." poetry show --tree

# 3. Validate pyproject.toml echo "Validating pyproject.toml..." python -c "import tomllib; tomllib.load(open('pyproject.toml', 'rb'))" || exit 1

# 4. Remove old lock echo "Removing old lock file..." rm -f poetry.lock

# 5. Fresh lock echo "Generating new lock file..." poetry lock -vvv || { echo "Lock failed. Trying with relaxed solver..." poetry config solver.use-poetry-solver false poetry lock }

# 6. Verify lock echo "Verifying lock file..." poetry lock --check || exit 1

# 7. Install echo "Installing dependencies..." poetry install --sync

echo "=== Resolution Complete ===" EOF

chmod +x scripts/poetry-resolve.sh

# Run resolution: ./scripts/poetry-resolve.sh

# Standard pyproject.toml structure: cat << 'EOF' > pyproject.toml.template [tool.poetry] name = "myproject" version = "0.1.0" description = "Project description" authors = ["Author <author@example.com>"]

[tool.poetry.dependencies] python = "^3.10" # Core dependencies with loose constraints requests = "^2.28" # Not ==2.28.0 flask = "^2.0" # Let transitive dependencies resolve themselves

[tool.poetry.group.dev.dependencies] pytest = "^7.0" black = "^23.0"

[build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" EOF

# Best practices for version constraints: # ^1.2.3 = >=1.2.3, <2.0.0 (allows minor/patch updates) # ~1.2.3 = >=1.2.3, <1.3.0 (allows patch updates only) # >=1.2.3 = any version >= 1.2.3 # 1.2.* = any version in 1.2.x series EOF ```

Poetry Dependency Checklist

CheckCommandExpected
Lock validpoetry lock --checkNo errors
No conflictspoetry show --treeNo conflicts shown
Version compatiblepoetry show pkgCompatible range
Hash matchlock --checkValid lock
Cache clearpoetry cache clearCache purged
Install successpoetry installAll packages installed

Verify the Fix

```bash # After resolving conflicts:

# 1. Generate lock file poetry lock # Output: Resolving dependencies... (complete)

# 2. Verify no conflicts poetry show --tree # Output: All dependencies resolved correctly

# 3. Check lock file validity poetry lock --check # Output: Lock file is valid and up to date

# 4. Install dependencies poetry install # Output: Installing dependencies... Complete

# 5. Test imports work poetry run python -c "import requests; print(requests.__version__)" # Output: 2.31.0 (or expected version)

# 6. Run tests poetry run pytest # All tests pass with new dependencies

# 7. Verify environment poetry env info # Path and Python version correct

# 8. Check dependency versions match expectations poetry show requests urllib3 # Both at compatible versions

# Compare before/after: # Before: SolverProblemError, version solving failed # After: Dependencies resolved, install successful ```

  • [Fix Python Pip Install Failed](/articles/fix-python-pip-install-failed)
  • [Fix Python Requirements Conflict](/articles/fix-python-requirements-conflict)
  • [Fix Python Module Not Found Error](/articles/fix-python-import-module-not-found-error-deep)