Skip to content

Fix: Pipenv Not Working — Lock File Generation, Shell Activation, and Dependency Resolution

FixDevs · (Updated: )

Part of:  Python Errors

Quick Answer

How to fix Pipenv errors — pipenv lock takes forever, Pipfile.lock not generated, shell activation broken, no virtualenv created, dependency conflict, and migration to uv or Poetry.

The Error

You install pipenv and try to lock — it hangs for hours:

$ pipenv lock
Locking [packages] dependencies...
# Spins for 30+ minutes, sometimes never completes

Or pipenv shell doesn’t activate:

$ pipenv shell
Spawning environment shell (/bin/bash)
# Shell opens but prompt doesn't show the venv name
# Or: command not found errors

Or the virtualenv lives in the wrong place:

$ pipenv install requests
# Creates venv in ~/.local/share/virtualenvs/myproject-XYZ123/
# But you wanted it in ./.venv/

Or dependency resolution conflicts:

Could not find a version that matches numpy<2.0,>=1.24
There are incompatible versions in the resolved dependencies

Or the Pipfile and Pipfile.lock get out of sync:

# Pipfile says: requests = "*"
# Pipfile.lock has: requests = "2.31.0"
# Someone manually edited the Pipfile but forgot to re-lock

Pipenv was the recommended Python dependency manager around 2018-2020 — combined Pipfile (human-readable) and Pipfile.lock (deterministic). It’s been overtaken by Poetry, uv, and PDM for new projects, but remains in widespread use. The biggest pain points are slow dependency resolution and venv location confusion. This guide covers each common issue and points to modern alternatives where appropriate.

Why This Happens

Pipenv uses pip’s resolver to find compatible versions. For large environments with many transitive dependencies, this resolution can take hours — sometimes never completes. The resolver explores the version space exhaustively without good heuristics, and it doesn’t print useful progress: you stare at “Locking…” for forty minutes with no clue whether it’s converging or thrashing through the same conflict tree.

Pipenv stores virtualenvs in a global cache directory (~/.local/share/virtualenvs/) by default, with a hashed name based on the project path. Moving the project directory invalidates the venv mapping; users get confused why a “fresh” venv is created in a new location. The same hashing is what makes Docker layers cache poorly — every container rebuild that changes the working directory recreates the venv from scratch.

Pipfile and Pipfile.lock drift is the third major source of pain. Pipenv expects you to edit the Pipfile through pipenv install/uninstall so the lock updates in lockstep. When humans hand-edit the Pipfile (faster, looks cleaner in PRs), the lock falls behind, and pipenv install --deploy in CI explodes with “Pipfile.lock out of date.” That’s often the first warning that the local and CI environments have diverged for days.

Production Incident Lens: When Pipenv Lock Freezes CI

The classic Pipenv production incident is silent: nobody touches dependencies for a week, then someone bumps requests in the Pipfile and pipenv lock in CI runs for two hours before the GitHub Actions runner times out. The pipeline goes red. The blast radius is every deploy that depends on this CI workflow — usually the entire service. Nobody can ship a hotfix until lock succeeds, and lock won’t succeed until you find the conflict.

When this hits at 3am, work the problem in this order. First, check whether the failure is reproducible locally: clone fresh, run pipenv lock --verbose and watch which package the resolver keeps backtracking on. Second, look at recent Pipfile commits — almost every “lock suddenly broke” incident traces to a constraint change in the last 24 hours (a new >=, a tightened upper bound, a new package whose deps conflict with existing ones). Third, if you cannot find the conflict in time, pin the entire dependency tree by running pipenv requirements > requirements.txt from the last green build’s lockfile and ship from pip install -r requirements.txt while you debug.

The right monitoring signal is lock duration over time. Plot pipenv lock wall-clock seconds from your CI logs as a daily metric. Once it crosses ~5 minutes, dependency resolution is degrading and you’re one bad constraint away from CI timeout. Most teams discover this only after the incident, by which point migrating to uv (Fix 8) is the only realistic path back to fast CI.

Fix 1: Installing Pipenv

# Recommended — pipx isolates pipenv from project dependencies
pipx install pipenv

# Or pip with --user
pip install --user pipenv

# macOS
brew install pipenv

Common Mistake: Installing pipenv with pip install pipenv (no --user) into the system Python. This pollutes the global environment and can break system tools. Always use pipx, pip install --user, or brew install.

Verify install:

pipenv --version
pipenv --where   # Project location (run from project dir)
pipenv --venv    # Virtualenv path

Fix 2: Initialize a Project

mkdir myproject && cd myproject

# Initialize with specific Python version
pipenv --python 3.12

# Install a package — creates Pipfile and Pipfile.lock
pipenv install requests
pipenv install pydantic pandas

# Install dev-only dependency
pipenv install --dev pytest ruff

Resulting Pipfile:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
requests = "*"
pydantic = "*"
pandas = "*"

[dev-packages]
pytest = "*"
ruff = "*"

[requires]
python_version = "3.12"

Pin specific versions:

pipenv install requests==2.31.0
pipenv install "pydantic>=2.0,<3.0"

Install from a git repository:

pipenv install -e git+https://github.com/user/repo.git@main#egg=mypackage

Install from a local path:

pipenv install -e ./local-package

Fix 3: Lock File Generation — When It Hangs

$ pipenv lock
Locking [packages] dependencies...
# Hours pass, no progress

Causes:

  1. Loose version constraintspackage = "*" lets pip explore every version
  2. Conflicting transitive deps — pip backtracks through many combinations
  3. Many packages — resolution complexity grows non-linearly

Reduce resolution time:

# Pre-clear the resolver cache
pipenv lock --clear

# Limit Python compatibility (smaller search space)
# In Pipfile:
[requires]
python_version = "3.12"   # Was "3"

# Pin major dependencies tighter
pipenv install "requests>=2.31,<3.0"

Switch to pip-tools if pipenv lock is unworkable — uses the same Pipfile concepts but pip-compile is faster:

pip install pip-tools

# requirements.in
requests
pydantic
pandas

# Generate lock
pip-compile requirements.in -o requirements.txt

Pro Tip: For new projects in 2025, use uv instead of pipenv. uv’s resolver is 100x faster on the same workloads — what takes pipenv 5 minutes (or never completes), uv finishes in seconds. For uv migration, see uv not working. Pipenv is in maintenance mode; new development should move off it.

Pro Tip: When CI lock starts trending past 60 seconds, treat it the same way you’d treat a latency regression — open a ticket, snapshot the Pipfile, and review the most recent constraint changes before it crosses the timeout threshold.

Skip the lock entirely for development:

pipenv install --skip-lock requests
# Faster install, but no lock file update — only for ephemeral envs

Fix 4: Virtualenv Location

Pipenv creates the venv in a global cache by default:

$ pipenv --venv
/Users/you/.local/share/virtualenvs/myproject-aBcDeF/

This path is hashed from the project directory — moving the project invalidates the venv mapping.

Force the venv inside the project directory:

# Set env var globally (recommended)
export PIPENV_VENV_IN_PROJECT=1

# Now `pipenv install` creates ./.venv/
cd myproject
pipenv install
ls .venv/   # Local venv

Add to your shell rc file:

# ~/.bashrc or ~/.zshrc
export PIPENV_VENV_IN_PROJECT=1

Common Mistake: Moving a project directory (or renaming it) and finding pipenv creates a brand new venv. The hash of the new path doesn’t match the cached one. Set PIPENV_VENV_IN_PROJECT=1 to make venvs travel with the project.

Delete the global venv if you no longer need it:

pipenv --rm
# Removes the venv associated with the current directory

Fix 5: Shell Activation

# Activate the venv in a subshell
pipenv shell

# Or run a command in the venv without activating
pipenv run python my_script.py
pipenv run pytest
pipenv run pip list

pipenv shell not working:

The most common cause is the shell environment not being correctly initialized. Check:

# What shell is pipenv using?
echo $SHELL

# Force a specific shell
SHELL=/bin/zsh pipenv shell

# Or use `pipenv run` which doesn't need shell activation
pipenv run python --version

For one-off commands, pipenv run is usually cleaner than pipenv shell:

pipenv run python -c "import requests; print(requests.__version__)"

Pro Tip: Prefer pipenv run for scripts and CI; use pipenv shell only for interactive development. run is more predictable — it doesn’t depend on shell hooks or env files. CI scripts that use pipenv shell often fail because the subshell doesn’t inherit CI variables correctly.

Fix 6: Pipfile vs Pipfile.lock

# Pipfile — human-edited, ranges
[packages]
requests = "*"            # Any version
pydantic = ">=2.0"        # 2.0 or higher
pandas = "~=2.2.0"        # Compatible release: >=2.2.0, <2.3.0
// Pipfile.lock — auto-generated, exact versions
{
    "_meta": {
        "hash": {"sha256": "..."}
    },
    "default": {
        "requests": {
            "version": "==2.31.0",
            "hashes": ["sha256:..."]
        }
    }
}

Workflow:

  1. Edit Pipfile (or use pipenv install/uninstall)
  2. pipenv lock regenerates Pipfile.lock
  3. Commit both files

Install from lock (reproducible install):

pipenv install --deploy --ignore-pipfile
# --deploy: fail if Pipfile.lock is out of date
# --ignore-pipfile: use only Pipfile.lock, don't re-resolve

This is the production install command — fast, deterministic.

Common Mistake: Editing Pipfile manually but not running pipenv lock. The Pipfile and lock file drift, and developers running pipenv install get different versions than intended. Always run pipenv lock after Pipfile edits — or use pipenv install which updates both.

Generate requirements.txt for tools that need it:

pipenv requirements > requirements.txt
pipenv requirements --dev > requirements-dev.txt

Useful for Docker builds where you don’t want to install pipenv in the image, or for tools that only accept requirements.txt.

Fix 7: Dependency Resolution Conflicts

Could not find a version that matches numpy<2.0,>=1.24

The resolver couldn’t find a version satisfying all constraints. Common causes:

  1. Transitive deps conflict — package A needs X >= 2, package B needs X < 2
  2. Python version too narrow — your python_version = "3.13" excludes a package only built up to 3.12
  3. Platform-specific packages — some wheels only exist for certain platforms

Diagnose:

pipenv graph
# Shows dependency tree with versions

pipenv graph --reverse
# Reverse: shows which packages depend on each

Manually relax constraints:

# Pipfile
[packages]
numpy = "*"      # Was "<2.0" — relax to let resolver succeed
pandas = "*"

Override a transitive dep:

[packages]
my-app = {file = ".", editable = true}
urllib3 = ">=2.0,<3.0"   # Force this version, overrides what other deps want

For database-driver dependency conflicts that surface during pipenv lock — particularly around PostgreSQL clients — see asyncpg not working for the patterns that translate over.

Fix 8: Migrating Off Pipenv

For active development moving away from pipenv, here are clean migration paths:

To Poetry:

pip install poetry
# Convert Pipfile to pyproject.toml manually, or use:
pip install dephell
dephell deps convert --from=pipfile --to=poetry

To uv:

# Generate requirements.txt from pipenv
pipenv requirements > requirements.txt
pipenv requirements --dev > requirements-dev.txt

# Initialize uv
uv init
uv add -r requirements.txt
uv add --dev -r requirements-dev.txt

To PDM:

pdm import   # Auto-detects Pipfile and converts

To plain pip + requirements.txt:

pipenv requirements > requirements.txt
pip install -r requirements.txt

For Poetry-specific patterns, see Poetry dependency conflict. For PDM-style projects, the import flow is similar.

Common Mistake: Trying to migrate without converting Pipfile.lock. The lock file contains exact versions you want to preserve; without porting them, the new tool re-resolves and may pick different versions. Use pipenv requirements to get current versions, then pin them in the new tool’s config.

Still Not Working?

Pipenv in 2025 — Is It Still Maintained?

Pipenv is still maintained (low pace) but no longer the recommended tool for new projects. The Python Packaging Authority (PyPA) now points to several alternatives. For existing pipenv projects:

  • Stable, working — fine to leave as-is
  • Active development — consider migrating for the resolver speed gains
  • New projects — use uv (recommended), Poetry, PDM, or Hatch

Docker Integration

FROM python:3.12-slim

RUN pip install pipenv

WORKDIR /app
COPY Pipfile Pipfile.lock ./
RUN pipenv install --deploy --system
# --system: install into the container's Python, not a venv

COPY . .
CMD ["python", "main.py"]

--system skips venv creation — Docker’s isolation makes the venv redundant. Faster builds, smaller images.

CI Integration

# .github/workflows/test.yml
- uses: actions/setup-python@v5
  with:
    python-version: "3.12"
- run: pip install pipenv
- run: pipenv install --deploy --dev
- run: pipenv run pytest

Cache the pipenv venv for faster CI:

- uses: actions/cache@v4
  with:
    path: ~/.local/share/virtualenvs
    key: pipenv-${{ runner.os }}-${{ hashFiles('Pipfile.lock') }}

For pre-commit hooks that need to run inside a pipenv-managed venv, install pre-commit in the same env (pipenv install --dev pre-commit) and invoke it via pipenv run pre-commit run --all-files.

Combining with Tox / Nox

# tox.ini
[testenv]
allowlist_externals = pipenv
commands = pipenv run pytest

Or generate requirements and let tox handle the install:

pipenv requirements > requirements.txt
# Then have tox install from requirements.txt directly

For matrix testing across Python versions, regenerate requirements.txt from pipenv and let tox or nox manage its own venvs — mixing two venv managers in the same project usually creates more problems than it solves.

Pipenv-Specific Workflow Tips

  • Use pipenv check to scan for known security vulnerabilities in installed packages
  • Use pipenv update to update all packages within their Pipfile constraints
  • Use pipenv clean to uninstall packages not in Pipfile.lock (useful after manual edits)
  • Use pipenv scripts (defined in Pipfile [scripts] section) for command shortcuts:
[scripts]
test = "pytest"
lint = "ruff check ."
serve = "uvicorn main:app --reload"
pipenv run test
pipenv run lint

Working with Multiple Python Versions

Pipenv respects pyenv if installed:

# Install Python 3.12 via pyenv
pyenv install 3.12.6

# Pipenv finds it automatically when you specify python_version
cd myproject
pipenv --python 3.12
# Uses pyenv-installed Python 3.12.6

If you have only one Python installed and Pipenv can’t find your desired version, it falls back to the system Python or fails — install the version first (via pyenv, uv, or system package manager).

Recovering From Broken State

If pipenv gets confused (corrupt cache, mismatched venv, weird errors):

# Nuclear option — delete venv and rebuild
pipenv --rm
pipenv install --dev

# Clear pip cache
pip cache purge

# If still broken, clear pipenv's own caches
rm -rf ~/.cache/pipenv/

Often faster than debugging the specific issue.

Pipfile Sources for Internal Indexes

For private package indexes (corporate PyPI mirrors, GitHub Packages):

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[[source]]
url = "https://internal.example.com/pypi/simple"
verify_ssl = true
name = "internal"

[packages]
public-package = "*"
private-package = {version = "*", index = "internal"}

The index = "internal" per-package directive picks which source to use. Without it, pipenv searches each index in order.

For pip-specific index configuration that interacts with pipenv, see pip could not build wheels.

Pipenv Lock Times Out in CI but Not Locally

Two things differ between your laptop and the CI runner: network latency to PyPI and the size of the pip resolver cache. A CI runner with a cold cache has to download every package’s metadata for every candidate version, while your laptop replays it from ~/.cache/pip. Mitigations:

  • Cache ~/.cache/pip and ~/.local/share/virtualenvs in CI keyed on hashFiles('Pipfile.lock').
  • Add --clear only when you actually need to invalidate; running it on every CI build re-downloads everything.
  • Use pipenv install --deploy --ignore-pipfile in CI rather than re-locking. Locking belongs on a developer machine or a dedicated lock-update workflow, not on every PR build.

Pipenv Is Frozen in a Half-Migrated State

Teams often start migrating from pipenv to uv, get interrupted, and end up with both Pipfile and pyproject.toml. Pick one source of truth before merging. If pyproject.toml is the future, delete Pipfile/Pipfile.lock only after uv sync succeeds locally and CI is green. Until then, treat the Pipfile as canonical and route every dependency change through it. Half-migrated repos are the single biggest source of “works on my machine” bugs in the post-pipenv world.

Pipenv Behind a Corporate Proxy or TLS Inspection

If pipenv install hangs on TLS handshake or fails with SSLError, your network is doing TLS inspection and pipenv doesn’t trust the inspector’s CA. Point pipenv at the bundle:

export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt

For internal mirrors, prefer [[source]] blocks in the Pipfile over PIP_INDEX_URL env vars — the source block is committed and reproducible, the env var only works on whatever shell remembers to set it.

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