Fix: error: externally-managed-environment (pip install)
The Error
You run pip install and get this:
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using, e.g.:
$ python3 -m venv path/to/venv
Then install packages within the virtual environment:
$ path/to/venv/bin/pip install xyz
note: If you believe this is a mistake, please contact your
Python installation provider.The exact wording varies by distro. On Fedora, it says dnf install instead of apt install. On macOS with Homebrew, the message references brew install.
Why This Happens
Your Linux distribution (or Homebrew on macOS) is protecting its system Python from pip.
This is caused by PEP 668, which was adopted in Python 3.11. Distributions that have implemented it include Ubuntu 23.04+, Debian 12+, Fedora 38+, Arch Linux, and macOS Homebrew.
The reason: Linux distributions ship dozens of system tools written in Python (apt, dnf, cloud-init, firewalld, and others). These tools depend on specific Python packages installed at specific versions through the system package manager. When you run pip install system-wide, pip can overwrite or remove those packages, breaking system tools in ways that are hard to diagnose.
Before PEP 668, a careless pip install --upgrade requests could break apt or dnf. Fixing it often meant reinstalling the OS. PEP 668 prevents this by marking the system Python as “externally managed.” When pip sees the marker file (EXTERNALLY-MANAGED in the Python installation directory, e.g., /usr/lib/python3.12/), it refuses to install packages.
This is not a bug. It is working as intended. The fix is to stop installing packages into the system Python.
Fix 1: Use a Virtual Environment (Recommended)
This is the correct fix for almost every case. A virtual environment gives you an isolated Python where you can install whatever you want without affecting the system.
Create and activate a virtual environment:
python3 -m venv .venv
source .venv/bin/activateNow pip works normally:
pip install requests flask pandasYour shell prompt will show (.venv) when the environment is active. All packages you install go into .venv/lib/ and won’t touch the system Python.
When you’re done working, deactivate:
deactivateMake it a habit
Create a venv for every project. This is standard practice in Python development and solves far more problems than just this error.
mkdir my-project && cd my-project
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtIf python3 -m venv fails
On Debian/Ubuntu, the venv module may not be installed by default:
Error: Command '[...] ensurepip' returned non-zero exit status 1.Install it:
sudo apt install python3-venvOn older Debian systems, you may also need:
sudo apt install python3-pip python3-venvFix 2: Use pipx for CLI Tools
If you’re installing a command-line tool like black, ruff, httpie, poetry, or ansible, use pipx. It installs each tool into its own isolated virtual environment automatically, so the tool is available globally without touching the system Python.
Install pipx:
# Ubuntu/Debian
sudo apt install pipx
pipx ensurepath
# Fedora
sudo dnf install pipx
pipx ensurepath
# macOS
brew install pipx
pipx ensurepathRestart your shell, then install tools with pipx instead of pip:
pipx install black
pipx install ruff
pipx install httpie
pipx install poetry
pipx install ansibleNow you can run black, ruff, etc. from anywhere. Each tool lives in its own venv under ~/.local/share/pipx/venvs/.
When to use pipx vs venv: Use pipx for tools you run from the command line. Use a venv for project dependencies (libraries you import in your code).
Fix 3: Use the —break-system-packages Flag (Not Recommended)
You can force pip to install into the system Python by passing --break-system-packages:
pip install --break-system-packages requestsOr set it permanently in your pip config:
mkdir -p ~/.config/pip
cat > ~/.config/pip/pip.conf << 'EOF'
[global]
break-system-packages = true
EOFWhy you shouldn’t do this: This flag exists for the exact reason the name implies. You are telling pip to break system packages. If you install a package that conflicts with a system dependency, you can break apt, dnf, or other system tools. Fixing this can require reinstalling Python system packages or, in severe cases, the entire OS.
The only time this is acceptable is in throwaway environments (Docker containers, CI runners, disposable VMs) where you control the entire system and don’t care if system tools break.
Fix 4: Use Your Distro’s Package Manager
If you need a common Python library for a system-wide script, install it through your distribution’s package manager:
# Ubuntu/Debian
sudo apt install python3-requests
sudo apt install python3-flask
sudo apt install python3-numpy
# Fedora
sudo dnf install python3-requests
sudo dnf install python3-flask
sudo dnf install python3-numpy
# Arch
sudo pacman -S python-requests
sudo pacman -S python-flask
sudo pacman -S python-numpyThe naming convention is python3-<package> on Debian/Ubuntu and Fedora, and python-<package> on Arch.
Limitations: Distro repositories carry a limited selection of packages, and the versions are often older than what’s on PyPI. If you need a specific version or a niche package, this won’t work. Use a venv instead.
To search for available Python packages:
# Ubuntu/Debian
apt search python3- | grep <package>
# Fedora
dnf search python3- | grep <package>Fix 5: Use pyenv or Conda for a Separate Python
If you need a Python installation that’s entirely yours—not managed by the OS—install one with pyenv or Conda. These install Python to your home directory, outside the system’s control, so pip works without restrictions.
pyenv
# Install pyenv
curl https://pyenv.run | bash
# Add to ~/.bashrc
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
# Restart shell, then install Python
pyenv install 3.12
pyenv global 3.12
# pip works without restrictions
pip install requestsConda (Miniconda)
# Install Miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh
# Create an environment
conda create -n myenv python=3.12
conda activate myenv
# pip works
pip install requestsWhen to use this: When you need a different Python version than what your distro ships, or when you work on multiple projects requiring different Python versions. pyenv is lighter weight. Conda is better if you also need non-Python dependencies (C libraries, CUDA, etc.).
Still Not Working?
Virtual environment inside Docker
If you’re building a Docker image based on Debian 12+ or Ubuntu 23.04+ and hitting this error in your Dockerfile, you have two options:
Option A: Use —break-system-packages (fine in Docker):
FROM python:3.12-slim
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txtWait—the official python:3.12-slim image does not trigger this error, because it’s built specifically for running pip. You only hit this when using a general-purpose base image:
# This WILL trigger the error:
FROM ubuntu:24.04
RUN apt update && apt install -y python3-pip
RUN pip install requests # error: externally-managed-environment
# Fix: use --break-system-packages (acceptable in Docker)
FROM ubuntu:24.04
RUN apt update && apt install -y python3-pip
RUN pip install --break-system-packages --no-cache-dir requests
# Better fix: use a venv even in Docker
FROM ubuntu:24.04
RUN apt update && apt install -y python3-pip python3-venv
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install --no-cache-dir requestsOption B: Use the official Python image. Switch your base image to python:3.12-slim or python:3.12 and avoid the problem entirely.
Homebrew Python on macOS
Homebrew’s Python also implements PEP 668. You’ll see the same error:
error: externally-managed-environmentThe fixes are identical: use a venv, pipx, or pyenv. Unlike Linux distros, Homebrew does not package individual Python libraries, so brew install python-requests won’t work. A venv is the most practical fix on macOS.
WSL2 on Windows
WSL2 runs a full Linux distribution, so you hit this error the same way you would on a native Linux install. The Ubuntu image in WSL2 is Ubuntu 24.04 by default, which enforces PEP 668.
All the fixes above work in WSL2. Use a venv:
python3 -m venv .venv
source .venv/bin/activate
pip install requestsIf python3-venv is missing:
sudo apt update && sudo apt install python3-venvCI/CD pipelines (GitHub Actions, GitLab CI)
If your CI pipeline uses a system Python on a modern runner image, you may hit this error. Fixes:
GitHub Actions: Use the setup-python action, which installs a standalone Python that doesn’t have PEP 668 restrictions:
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install -r requirements.txt # works fineGitLab CI: Use a Python Docker image:
image: python:3.12-slim
script:
- pip install -r requirements.txtGeneric CI: If you must use the system Python, either create a venv or use --break-system-packages:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtRemoving the EXTERNALLY-MANAGED file (don’t)
You may see advice to delete the marker file:
sudo rm /usr/lib/python3.*/EXTERNALLY-MANAGEDThis removes the protection and makes pip work system-wide again. Don’t do this. It defeats the purpose of PEP 668 and puts your system packages at risk. If a future system update restores the file, you’ll be back where you started. Use a venv.
Related Articles
Fix: ERROR: Could not build wheels / Failed building wheel (pip)
How to fix pip 'ERROR: Could not build wheels', 'Failed building wheel', 'No matching distribution found', and 'error: subprocess-exited-with-error'. Covers missing C compilers, build tools, system libraries, Python version issues, pre-built wheels, and platform-specific fixes for Linux, macOS, and Windows.
Fix: pip No Matching Distribution Found for <package>
How to fix the pip error 'No matching distribution found' when installing Python packages, including version conflicts, platform issues, and index problems.
Fix: python: command not found (or python3: No such file or directory)
How to fix 'python: command not found', 'python3: command not found', and wrong Python version errors on Linux, macOS, Windows, and Docker. Covers PATH, symlinks, pyenv, update-alternatives, Homebrew, and more.
Fix: SSL certificate problem: unable to get local issuer certificate
How to fix 'SSL certificate problem: unable to get local issuer certificate', 'CERT_HAS_EXPIRED', 'ERR_CERT_AUTHORITY_INVALID', and 'self signed certificate in certificate chain' errors in Git, curl, Node.js, Python, Docker, and more. Covers CA certificates, corporate proxies, Let's Encrypt, certificate chains, and self-signed certs.