Skip to content

Fix: Python venv Using Wrong Python Version

FixDevs · (Updated: )

Part of:  Python Errors

Quick Answer

How to fix Python virtual environments using the wrong Python version — venv picking system Python instead of pyenv, specifying the interpreter path, and verifying the active environment.

The Error

You create a virtual environment expecting Python 3.11 but get 3.9 (or another version):

python -m venv .venv
source .venv/bin/activate
python --version
# Python 3.9.7  ← Expected 3.11

Or you install a package that requires Python 3.10+ but it fails:

ERROR: Package 'some-package' requires a different Python: 3.9.7 not in '>=3.10'

Or pyenv shows the right version but the venv still uses the system Python:

pyenv version
# 3.11.8 (set by /home/user/project/.python-version)

python -m venv .venv
source .venv/bin/activate
python --version
# Python 3.9.18  ← Still wrong

Or after activating the venv, which python points outside the venv:

which python
# /usr/bin/python3  ← Should be /home/user/project/.venv/bin/python

Why This Happens

Virtual environments are created using whichever Python binary runs python -m venv. The resulting environment is permanently tied to that specific Python binary:

  • python command resolves to the wrong binarypython may point to Python 3.9 while python3 or python3.11 points to a newer version.
  • pyenv shims not in PATH or not initialized — pyenv works by inserting shims at the beginning of PATH. If pyenv’s init isn’t in your shell profile, the shims don’t activate and the system Python is used instead.
  • Shell profile not reloaded — you installed a new Python version but haven’t restarted your shell or run source ~/.bashrc.
  • python -m venv called before activating pyenv — if you run python -m venv .venv in a script or CI pipeline without first sourcing pyenv, it uses the system Python.
  • Conda base environment active — Conda’s base environment may intercept python and return its own version, regardless of pyenv settings.
  • venv already created with the wrong Python — once a venv is created, its Python version is fixed. Deleting and recreating is the only way to change it.

The root of nearly every reported case is the same: python -m venv does not consult .python-version or any project-level configuration. It only looks at the Python interpreter that is currently running. If that interpreter is the wrong one — because pyenv was not initialized, because Conda hijacked PATH, because Homebrew put /opt/homebrew/bin ahead of pyenv — then your venv is wrong from the moment of creation. No amount of editing .python-version after the fact will change it.

The second class of confusion is system-managed Python protection, which appeared in 2022. Modern Linux distributions (Debian 12, Ubuntu 23.04+, Fedora 38+) ship Python with a PEP 668 marker that blocks pip install outside a virtual environment. Users see “externally-managed-environment” and panic-create a venv, often with the wrong Python because they ran python -m venv instead of python3.11 -m venv. The PEP 668 protection is not the cause of the wrong-version problem, but the two errors arrive in the same week of a fresh-OS install and get conflated.

The third pattern is invisible inheritance from CI/CD. A Dockerfile that says FROM python:3.11 actually pins to the latest 3.11.x at image-build time. If you rebuild a year later and the base image now ships 3.11.10 instead of 3.11.4, your venv silently bumps. This is rarely the cause of “wrong Python” but is sometimes the cause of “the same code that worked yesterday now fails.” If the Python in your venv changed between deploys, check the base image SHA, not your code.

Version History That Changes the Failure Mode

The Python ecosystem’s tooling for environment isolation has shifted radically. Knowing which tool generation you are on changes the diagnosis.

virtualenv (2007). The original third-party tool. Required a separate install, copied (or symlinked) the Python interpreter into the env directory. Still maintained, still works, still used by tox, nox, and a few other test runners.

venv standard library (Python 3.3, March 2012). Built into Python from 3.3 onward. Simpler, faster, no install needed. From 3.3 to today, python -m venv .venv is the canonical answer for a single-language Python project. The difference between venv and virtualenv is mostly invisible — virtualenv has more bells and whistles (alternative Python versions in one command, faster bootstrap, more isolation), but for most workflows they are interchangeable.

pyenv (2012 onward). Shim-based version manager. Lets you install multiple Python versions side by side and switch via .python-version. The fact that pyenv installs into ~/.pyenv/versions/3.11.8/bin/python and inserts shims into PATH is what makes python -m venv Just Work — but only if pyenv is initialized in your shell. The single most common pyenv-related “wrong version” report traces to eval "$(pyenv init -)" missing from ~/.bashrc or ~/.zshrc.

pipx 1.0 (December 2021). Tool for installing Python applications in isolated environments. Not strictly an environment manager for your project, but its arrival changed the recommended pattern for installing poetry, black, and httpie. If you pipx install poetry, the Poetry binary lives in a venv pipx created — separate from your project venv.

PEP 668 — externally-managed-environments (Python 3.11+, January 2022). Lets distros mark their system Python as off-limits for pip install. Ubuntu 23.04, Debian 12, Fedora 38, Arch (since 2023). Affects you indirectly: when users hit the externally-managed error, they create a venv as the fix, and that venv often uses the wrong Python because they ran the system-bound python -m venv rather than python3.11 -m venv.

uv (February 2024, Astral). Written in Rust. Fast. Combines venv creation, package install, and Python version management in one binary. uv venv --python 3.11.8 will download and install Python 3.11.8 if it is not already on the system. From a “wrong Python version” perspective, uv essentially closes the gap pyenv covers: you no longer need a separate version manager. If your team is on uv in 2026, the right answer to this entire error is uv venv --python 3.11.

uv 0.4 (October 2024). Added uv python install for explicit version management, decoupled from venv creation. This is the version that made uv a viable full replacement for pyenv + venv.

Poetry version pin behavior. Poetry has always written the chosen Python version into pyproject.toml, and the venv it creates inherits that. Recent Poetry (1.5+) auto-recreates a venv when the pinned version changes — older Poetry would silently use the old venv.

Conda environment isolation. Conda predates most of the above and operates differently — it manages binary packages, including the Python interpreter, in dedicated env directories under ~/anaconda3/envs/. Conda’s base environment is the one that hijacks PATH and causes most “pyenv works but python -m venv is wrong” reports. Run conda config --set auto_activate_base false to stop this, then conda deactivate for the current shell.

Fix 1: Specify the Python Binary Explicitly

The most reliable fix is to call the exact Python binary you want when creating the venv:

# Use the full path to the desired Python
/usr/bin/python3.11 -m venv .venv

# Or use the versioned command directly
python3.11 -m venv .venv
python3.10 -m venv .venv

# Verify the result
source .venv/bin/activate
python --version  # Should now show the correct version

Find available Python binaries:

# List Python binaries on the system
ls /usr/bin/python*
ls /usr/local/bin/python*

# Use 'which' to find a specific version
which python3.11
which python3.12

Fix 2: Fix pyenv Not Working

If you use pyenv but the venv still uses the system Python, fix the pyenv initialization:

# Check if pyenv is properly initialized
pyenv version
# If this fails or shows 'system', pyenv is not active

# Check if pyenv shims are in PATH
echo $PATH | tr ':' '\n' | grep pyenv
# Should see something like: /home/user/.pyenv/shims

# Initialize pyenv in your shell profile
cat ~/.bashrc  # or ~/.zshrc, ~/.bash_profile
# Should contain:
# export PYENV_ROOT="$HOME/.pyenv"
# export PATH="$PYENV_ROOT/bin:$PATH"
# eval "$(pyenv init -)"

Add pyenv initialization to your shell profile:

# For bash — add to ~/.bashrc or ~/.bash_profile
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
source ~/.bashrc

# For zsh — add to ~/.zshrc
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
source ~/.zshrc

After initializing pyenv, verify it works:

# Verify pyenv is active
pyenv version
# 3.11.8 (set by /home/user/project/.python-version)

# Check which python pyenv resolves to
pyenv which python
# /home/user/.pyenv/versions/3.11.8/bin/python

# Now create the venv — it will use pyenv's Python
python -m venv .venv
source .venv/bin/activate
python --version
# Python 3.11.8

Install the Python version you need with pyenv:

# List available versions
pyenv install --list | grep "3.11"

# Install a specific version
pyenv install 3.11.8

# Set it globally (all projects)
pyenv global 3.11.8

# Set it for the current project only (creates .python-version file)
pyenv local 3.11.8

# Verify
python --version  # 3.11.8

Fix 3: Delete and Recreate the venv

Once a venv is created, its Python version is baked in and cannot be changed. Delete and recreate it with the correct Python:

# Deactivate the current venv if active
deactivate

# Delete the venv
rm -rf .venv

# Recreate with the correct Python
python3.11 -m venv .venv

# Or with pyenv active:
pyenv local 3.11.8
python -m venv .venv

# Activate and verify
source .venv/bin/activate
python --version
# Python 3.11.8

# Reinstall dependencies
pip install -r requirements.txt

Fix 4: Fix the PATH Order

If multiple Python installations conflict, PATH order determines which python command is found first:

# See the full resolution order
echo $PATH | tr ':' '\n'

# See which python is found
which python
which python3
which python3.11

# If pyenv shims aren't first, fix PATH order
# pyenv shims must come before /usr/bin
export PATH="$HOME/.pyenv/shims:$HOME/.pyenv/bin:$PATH"

Check for Conda interference:

# If Conda is active, it prepends its bin directory to PATH
conda info
# Shows: active environment

# Deactivate Conda base environment
conda deactivate

# Or configure Conda to not activate base by default
conda config --set auto_activate_base false

macOS — Homebrew Python conflicts:

# Homebrew installs Python at:
ls /opt/homebrew/bin/python*    # Apple Silicon
ls /usr/local/bin/python*       # Intel

# Set up PATH to prefer pyenv over Homebrew
# In ~/.zshrc:
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"    # pyenv first
eval "$(pyenv init -)"
# Homebrew's python3 comes after pyenv in PATH

Fix 5: Verify the Active venv

After activating a venv, verify all Python-related commands resolve inside the venv:

source .venv/bin/activate

# All of these should point inside .venv/
which python
# /home/user/project/.venv/bin/python

which pip
# /home/user/project/.venv/bin/pip

python --version
# Python 3.11.8

pip --version
# pip 23.x.x from /home/user/project/.venv/lib/python3.11/site-packages/pip (python 3.11)

# Confirm the venv's Python binary and its version
python -c "import sys; print(sys.executable, sys.version)"
# /home/user/project/.venv/bin/python 3.11.8 (...)

Check if the venv is actually active:

# The VIRTUAL_ENV environment variable is set when a venv is active
echo $VIRTUAL_ENV
# /home/user/project/.venv  ← Active
# (empty) ← Not active

# The prompt usually shows the venv name
# (.venv) user@host:~/project$ ← Active

Fix 6: Use python -m venv with a Specific Version in CI/CD

In CI/CD pipelines, always specify the exact Python version to avoid using whatever is installed by default:

# GitHub Actions
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'   # Exact version — not 'python3' or '3.x'

      - name: Create venv
        run: python -m venv .venv  # Uses the Python set by setup-python

      - name: Install dependencies
        run: |
          source .venv/bin/activate
          pip install -r requirements.txt
# GitLab CI
test:
  image: python:3.11-slim   # Pin the Python version in the Docker image
  script:
    - python --version       # Verify
    - python -m venv .venv
    - source .venv/bin/activate
    - pip install -r requirements.txt

In Docker:

# Pin the exact Python version in the base image
FROM python:3.11.8-slim

# This sets the default python command to 3.11.8
RUN python --version  # Python 3.11.8

WORKDIR /app
COPY requirements.txt .
RUN python -m venv .venv && \
    .venv/bin/pip install --no-cache-dir -r requirements.txt

# Use the venv's Python explicitly
CMD [".venv/bin/python", "app.py"]

Fix 7: Use Poetry or uv for Automatic Version Management

Modern Python package managers handle Python version selection automatically:

Poetry:

# pyproject.toml — specify Python version constraint
[tool.poetry.dependencies]
python = "^3.11"   # Requires Python 3.11 or higher
# Poetry creates the venv with a compatible Python
poetry env use python3.11  # Explicitly set the Python version
poetry env info             # Shows which Python Poetry is using

uv (modern, fast Python package manager):

# uv automatically finds and uses the right Python
uv venv --python 3.11 .venv        # Create venv with Python 3.11
uv venv --python /path/to/python   # Or use a specific binary

# Or in pyproject.toml
# [project]
# requires-python = ">=3.11"
# Then:
uv venv    # uv selects a compatible Python automatically

Still Not Working?

Check if the venv’s pyvenv.cfg shows the right version:

cat .venv/pyvenv.cfg
# home = /usr/bin           ← Where the Python was found (wrong if not 3.11)
# version = 3.9.7           ← The Python version (wrong)
# version_info = 3.9.7.final.0

If it shows the wrong version, the venv must be recreated.

Check for a .python-version file in a parent directory — pyenv reads .python-version from the current directory up to the root. A .python-version in a parent directory may override your local settings:

# Find all .python-version files from current dir upward
ls -la .python-version 2>/dev/null || echo "Not here"
ls -la ../.python-version 2>/dev/null || echo "Not in parent"

# The effective pyenv version
pyenv version
# Shows which .python-version file is controlling the version

Restart your shell after modifying shell profile files. Changes to ~/.bashrc, ~/.zshrc, or ~/.bash_profile don’t take effect until you start a new shell session or run source ~/.bashrc.

Replace pyenv + venv with uv entirely. If you keep hitting “wrong Python” reports across the team, the structural fix in 2026 is to migrate to uv. A single binary handles Python version download, venv creation, and dependency install. The .python-version file is still read, but the resolution path is shorter and there is no shim layer to forget to initialize:

# Install uv (one-time, per developer)
curl -LsSf https://astral.sh/uv/install.sh | sh

# In any project:
uv python install 3.11.8        # Downloads Python 3.11.8 if missing
uv venv --python 3.11.8         # Creates .venv with that version
uv pip install -r requirements.txt

See Fix: uv Not Working for installation gotchas. On a fresh machine, this is fewer moving parts than the pyenv + venv chain.

Check for a stale __pycache__ confusing the interpreter. Rare, but if you switched Python versions and started seeing ImportError or wrong-version behavior after activating the venv, the __pycache__ directories may contain bytecode compiled for the old Python. Run find . -name __pycache__ -exec rm -rf {} + and try again.

Conda’s base env is still active. If (base) appears in your prompt and you have already run conda deactivate once, you may need to run it twice — pyenv shims can re-trigger Conda activation. The permanent fix is conda config --set auto_activate_base false followed by a shell restart. See Fix: Conda Not Working for related Conda issues.

For related Python environment issues, see Fix: Python ModuleNotFoundError (venv) and Fix: pip No Matching Distribution Found.

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