pip “externally-managed-environment” Error: Fix It Properly (with uv)
Why pip says externally-managed-environment on Ubuntu, Debian, Homebrew and WSL, why --break-system-packages is a trap, and the clean fixes, tested in Docker.
error: externally-managed-environment means the Python you are installing into belongs to your operating system’s package manager, which has asked pip not to touch it. Nothing is broken. The fix is to install into an environment of your own: a virtual environment for a project (with python3 -m venv, or uv), pipx or uv tool for command-line tools, and apt only for packages your system itself needs.
Everything here was tested on 26 October 2026 in fresh Docker containers of Debian 12 and 13 and Ubuntu 24.04 and 26.04, in the official python:3.13-slim and python:3.14-slim images, and with Homebrew’s Python 3.13 on macOS, using uv 0.13.5.
The error
On Debian and Ubuntu — and so on most WSL installations, which run Ubuntu — pip install requests stops with this. It was the same on all four releases tested, apart from the Python version in the README.venv line:
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 python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you. Make sure you have pipx installed.
See /usr/share/doc/python3.12/README.venv for more information.
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
Homebrew’s Python on macOS shows its own version: it suggests brew install xyz, a virtual environment, or brew install pipx. The message tells you what to do; the rest of this article explains why, and which option fits.
Why it happens: PEP 668
Debian, Ubuntu and Homebrew ship a Python that their own tools depend on. A pip install into that Python can replace a library one of those tools needs, and pip and the system package manager don’t know about each other’s files. PEP 668 gives distributions a way to say “hands off”: a file called EXTERNALLY-MANAGED in the Python’s standard-library directory. When pip finds it, it refuses to install, and prints the message from that file.
You can see the directory with:
python3 -c "import sysconfig; print(sysconfig.get_path('stdlib'))"
| System | Python | Marker |
|---|---|---|
| Debian 12 | 3.11.2 | /usr/lib/python3.11/EXTERNALLY-MANAGED |
| Debian 13 | 3.13.5 | /usr/lib/python3.13/EXTERNALLY-MANAGED |
| Ubuntu 24.04 | 3.12.3 | /usr/lib/python3.12/EXTERNALLY-MANAGED |
| Ubuntu 26.04 | 3.14.4 | /usr/lib/python3.14/EXTERNALLY-MANAGED |
| Homebrew on macOS | 3.13.5 | in Homebrew’s python3.13 standard-library folder |
python:3.13-slim, python:3.14-slim images |
3.13.15, 3.14.9 | none |
Debian 12 and Ubuntu 23.04, both released in 2023, were the first to ship the marker, which is why older tutorials never mention the error.
pip install --user doesn’t get around it: it failed with the same error everywhere. That is deliberate. PEP 668 covers user installs too, because packages in your home directory are also on the system Python’s path.
Don’t switch the check off
pip install --break-system-packages requests # works, but can break apt-managed tools later
sudo rm /usr/lib/python3.*/EXTERNALLY-MANAGED # removes the protection entirely
Both make the message go away by removing the safety check, not the problem. The breakage, if it comes, shows up later and somewhere else: a system tool that fails after an unrelated install, or a distribution upgrade that trips over files it didn’t put there.
The check can also be switched off without anyone typing that flag. A break-system-packages = true line in a pip config file, or PIP_BREAK_SYSTEM_PACKAGES=1 in the environment, has the same effect on every install; both were tested. If you never see this error on a system where you would expect it, run pip config list and check your environment.
Fix 1: a virtual environment (built in)
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install requests
On Debian and Ubuntu, the first command fails until you install the venv module, which the distributions package separately:
The virtual environment was not created successfully because ensurepip is not
available. On Debian/Ubuntu systems, you need to install the python3-venv
package using the following command.
sudo apt install python3-venv fixes it; after that, the commands above installed requests into .venv on all four releases.
Fix 2: uv, which creates the environment for you
uv is a package and project manager for Python, written in Rust. It creates and uses a virtual environment for you, so the error can’t happen, and its makers describe it as “10-100x faster than pip” and “a single tool to replace pip, pip-tools, pipx, poetry, pyenv, twine, virtualenv, and more”.
Install it on macOS or Linux (on Windows, the uv documentation has a PowerShell command):
curl -LsSf https://astral.sh/uv/install.sh | sh
The installer puts uv in ~/.local/bin; open a new terminal, or run source $HOME/.local/bin/env, before using it.
For a project
uv init myapp && cd myapp
uv add requests # creates .venv, adds requests to pyproject.toml, writes uv.lock
uv run myapp # runs the project's command inside .venv; no activate needed
uv run fetch.py # runs any of your scripts the same way
Older guides end with uv run main.py. That doesn’t work for a new project: in uv 0.13.5, uv init creates a package with its code in src/myapp/ and a myapp command, and no main.py at all — uv run main.py fails with Failed to spawn: main.py. Use uv init --no-package if you want the old single-file layout.
For a one-off script
uv run --with requests script.py
uv installs requests into a temporary environment for that run only.
For an existing requirements.txt
uv venv
uv pip install -r requirements.txt
Without the uv venv step, uv stops with No virtual environment found. And uv respects the marker too: uv pip install --system requests fails with The interpreter at /usr is externally managed.
For a different Python version
uv python install 3.13
uv venv --python 3.13
On Ubuntu 24.04, whose system Python is 3.12, this downloaded CPython 3.13.17 and created a 3.13 environment without touching the system Python.
Fix 3: command-line tools with uv tool or pipx
If what you want is a command — ruff, black, httpie, yt-dlp — rather than a library to import, give each tool its own isolated environment:
uv tool install ruff # puts ruff on your PATH (in ~/.local/bin)
uvx ruff check . # or run it once without installing it
pipx does the same. On Debian and Ubuntu, install it with sudo apt install pipx, then pipx install httpie; on macOS, brew install pipx.
Fix 4: a library your system itself needs
When the package is a dependency of something you installed with apt — or you really want it available to the system Python — install the distribution’s package:
sudo apt install python3-requests
Expect an older version: in testing, apt installed requests 2.31.0 on Ubuntu 24.04 and 2.28.1 on Debian 12, when the current release on PyPI was 2.34.2. For your own projects, a virtual environment gives you the version you ask for. On macOS, brew install <formula> plays the same role when a formula exists.
In Docker
The official python images install Python under /usr/local without the marker, so pip install works there (it warns about running as root). A plain debian or ubuntu image with apt install python3 has the marker, and you get the error. Either base your image on python, create a virtual environment in the Dockerfile, or use uv:
FROM python:3.13-slim
COPY --from=ghcr.io/astral-sh/uv:0.13.5 /uv /uvx /bin/
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --locked --no-dev --no-install-project
COPY . .
RUN uv sync --locked --no-dev
ENV PATH="/app/.venv/bin:$PATH"
CMD ["myapp"]
The first uv sync installs only the dependencies, so Docker can cache that layer until uv.lock changes; the second installs your project once its code has been copied in. Three details matter, and each was tested:
--no-install-projectin the first sync. Without it, a project made byuv initfails to build:Expected a Python module at: src/myapp/__init__.py, because the code isn’t in the image yet.- Run the app from
.venv, not withuv run.uv runsyncs the environment before it starts, including dev dependencies the image left out. WithCMD ["uv", "run", "main.py"], the container downloaded pytest and its dependencies on every start, and failed to start at all without network access. The Dockerfile above started without a network. - Pin the uv version (
uv:0.13.5, notuv:latest), as uv’s own Docker guide recommends, so a new uv release can’t change your build.
Which fix should you use?
| Situation | Use |
|---|---|
| A project with dependencies | uv add, or python3 -m venv |
| A quick script | uv run --with package script.py |
| A command-line tool | uv tool install, or pipx install |
| A dependency of a system tool | sudo apt install python3-xyz |
| A Docker image | the python image, or uv with the Dockerfile above |
Checklist
- Read the error as advice, not as a bug: the system Python isn’t yours to install into.
- Never use
--break-system-packagesor deleteEXTERNALLY-MANAGED; checkpip config listfor a setting that does it for you. - Projects:
python3 -m venv .venv(aftersudo apt install python3-venv), or uv. - With uv:
uv init,uv add,uv run myapp;uv run --withfor one-off scripts. - Tools:
uv tool installor pipx. - System libraries:
apt install python3-xyz, and expect older versions. - Docker: install with
--no-install-projectfirst, run from.venv, pin the uv image.
References and further reading
- PEP 668: Marking Python base environments as “externally managed”, Python Enhancement Proposals
- uv documentation, Astral
- Using uv in Docker, uv documentation
- venv: creation of virtual environments, Python documentation
- pipx, Python Packaging Authority