On Ubuntu 23.04+, Debian 12+ and other modern distributions, running pip install outside a virtual environment fails:

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.

This isn’t a bug. It’s a deliberate safeguard (PEP 668) — and the fix is to install packages in the right place, not to force them into the system.

Why it happens

The system Python belongs to the distribution: tools like apt, cloud-init, netplan and many system utilities are written in Python and depend on specific library versions installed by apt. sudo pip install used to overwrite those libraries, sometimes breaking the OS in subtle ways. The distribution now marks its Python as “externally managed”, and pip respects that.

Fix 1: use a virtual environment (for projects)

The standard answer for any application or project:

sudo apt install -y python3-venv
python3 -m venv ~/myproject/.venv
source ~/myproject/.venv/bin/activate
pip install requests flask

Inside the venv, pip works normally. In scripts, cron jobs and systemd services, call the venv’s interpreter directly (~/myproject/.venv/bin/python). Full guide: Python virtual environments.

Fix 2: use pipx (for command-line tools)

For Python applications you want on your PATH — httpie, ansible, black, yt-dlp, poetry — use pipx. It creates an isolated venv for each tool automatically:

sudo apt install -y pipx
pipx ensurepath
pipx install httpie
http --version

Upgrade all tools with pipx upgrade-all.

Fix 3: install the distribution package

Many popular libraries are packaged by the distribution:

apt search python3-requests
sudo apt install -y python3-requests python3-yaml

Good for scripts that should use only system packages; versions follow the distribution’s release.

Fix 4: uv (fast, modern)

uv manages virtual environments and packages very quickly, and never touches the system Python:

curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv
uv pip install -r requirements.txt
uv tool install ruff        # like pipx

Escape hatches (use sparingly)

User installs: pip install --user is also blocked on externally managed systems.

--break-system-packages:

pip install --break-system-packages somepackage

This forces the install. It’s acceptable in disposable environments — a Docker image built on a distro base image that isn’t used for anything else — but on a real server it reintroduces exactly the risk the safeguard prevents. Never combine it with sudo on a server you care about.

Removing the EXTERNALLY-MANAGED marker file has the same effect for everything and is strongly discouraged.

In Docker images

Official python:3.x images don’t use the distribution’s Python, so pip works without the error. If you build on ubuntu or debian base images and use the system Python, either create a venv in the image (cleanest) or use --break-system-packages inside that single-purpose image.

Which fix for which situation?

Situation Use
Web app, bot, script with dependencies Virtual environment (or uv)
CLI tool you want everywhere pipx (or uv tool install)
Simple system script, common library apt install python3-…
Throwaway container venv, or --break-system-packages

Related: installing Python on Ubuntu and deploying Flask with Gunicorn.

  • Python
  • pip
  • Ubuntu