"Why did pip install suddenly start failing when it worked yesterday?"
Many people hit this screen after upgrading Ubuntu to 23.04 or later, switching to Debian 12 (bookworm), or updating Homebrew Python to 3.12 on macOS.
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.
...
note: If you believe this is a mistake, please contact your
Python installation or OS distribution provider.
hint: See PEP 668 for the detailed specification.To cut to the chase: this is not a bug — it is an intentional policy change. Python is not misinstalled, and you did not type the command wrong. Your distro planted an EXTERNALLY-MANAGED marker file to protect the system Python, and pip detects it and refuses a system-wide install.
This post covers (1) why the install is blocked, in 30 seconds, (2) a decision table so you can pick the right fix for your situation, and (3) copy-paste commands you can run immediately. It also explains why the dangerous workarounds that can break your system are dangerous.
Why this error exists — PEP 668 in 30 seconds
The identity of externally-managed-environment is simple. It is a safety mechanism that stops pip from freely injecting packages into a Python environment managed by an OS package manager such as apt, dnf, or brew.
In the past you could install any package into the system Python with sudo pip install. The problem was that apt-installed python3-requests and pip-installed requests collided in the same directory, repeatedly breaking apt itself or system utilities (for example apt, netplan, ubuntu-drivers). PEP 668 was introduced to prevent that, and pip now refuses to install when it detects a marker file at these locations:
- Debian/Ubuntu:
/usr/lib/python3.11/EXTERNALLY-MANAGED(3.11/3.12 etc. depending on version) - Homebrew:
/opt/homebrew/lib/python3.12/EXTERNALLY-MANAGED(or/usr/local/...)
Representative versions where this started applying:
| Environment | When it started |
|---|---|
| Ubuntu | 23.04 and later (including 23.10, 24.04 LTS) |
| Debian | 12 (bookworm) and later |
| Fedora | Applied in recent releases |
| Homebrew Python | Enabled by default from 3.12+ |
In other words, the command did not suddenly fail because of something you did — the OS changed the rules. Once you understand the rules, the fix is clear.
30-second decision table — which fix should you use?
Do not jump straight to --break-system-packages. Identify which of the following situations you are in, and the fix is determined.
| Your situation | Recommended fix | Why |
|---|---|---|
| You want it as a system-wide library | apt install python3-<package> or a venv | The apt version is safe and will not collide with system tools |
| It is for developing a specific project | venv | Per-project isolation and reproducibility (the most standard approach) |
| You only want CLI tools such as black/httpie | pipx | Automatic isolation per tool, PATH registration included |
| You are inside Docker/CI | venv, or a controlled --break-system-packages | Throwaway, isolated environment, so contamination risk is low |
| You want a fast, modern dev environment | uv | Rust-based speed plus automatic venv management |
Once you have found your row in the table, jump to the matching solution section below.
Exact commands and trade-offs for each solution
(a) venv — the standard and safest answer
If you need packages for a specific project, this is the right answer about 90% of the time.
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install requestsExpected successful result: (.venv) appears in front of your prompt, and pip install completes with no warnings. which python should print a path like .../.venv/bin/python.
- Pros: never touches the system Python; pins versions per project for reproducibility
- Trade-off: you must activate with
source .venv/bin/activateevery time you open the project
If python3 -m venv itself errors with ensurepip is not available, on Debian/Ubuntu you need to install sudo apt install python3-venv first.
(b) pipx — for CLI tools only
If you only need tools you run from the command line, such as black, httpie, poetry, or ruff, pipx is the best fit. It automatically creates an isolated venv per tool, so there are no dependency conflicts.
sudo apt install pipx # 또는 brew install pipx
pipx ensurepath
pipx install httpieAfter running pipx ensurepath, open a new terminal or run source ~/.bashrc so PATH is updated. After that you can run commands like http https://example.com directly.
- Pros: automatic isolation per tool; upgrades and uninstalls are clean with
pipx upgrade httpie/pipx uninstall httpie - Trade-off: not suitable for installing libraries you
import(executables only)
(c) --break-system-packages — temporary / Docker only
The name means exactly what it says: "I am going to break system package protection." Live up to that name and use it carefully.
pip install --break-system-packages requestsPrefer combining it with --user so packages go into the user home (~/.local) instead of system directories — that is somewhat less risky.
pip install --user --break-system-packages requests- Acceptable situations: a personal throwaway environment, inside a Docker image
- ⚠️ Do not use: the system Python on a production server. If files overlap with apt packages, OS tools can break.
(d) Global relaxation via pip.conf — not recommended, only when necessary
If typing the option every time is annoying, you can relax it permanently via a config file. That turns the safety mechanism off all the time, so limit this to a personal development machine.
# ~/.config/pip/pip.conf
[global]
break-system-packages = true- Trade-off: permanently disables PEP 668 protection. Never use this on servers or shared machines.
(e) uv — a fast, modern development environment
A Rust-based tool from Astral that replaces pip/venv and has been adopted quickly. Install and dependency resolution are much faster than pip.
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv
uv pip install requestsuv venv automatically creates .venv, and uv pip install installs into it. You can run uv run python script.py without a separate activate step.
- Pros: outstanding speed, automatic venv management,
pyproject.tomlintegration - Trade-off: learning cost of a new tool; you need team buy-in to adopt it org-wide
Recommended Docker/CI pattern
Containers are already isolated, throwaway environments, so the approach is a bit different. The canonical pattern is creating a dedicated venv inside the image and putting it on PATH.
FROM python:3.12-slim
# 전용 venv 생성 후 PATH 선점 → 이후 pip/python은 자동으로 venv 사용
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install -r requirements.txtExample requirements.txt:
requests==2.32.3If you consider the base image already isolated, pip install --break-system-packages -r requirements.txt is also commonly used in practice. The venv pattern is still more explicit and safer.
When the build fails: if CI logs show externally-managed-environment, switch to one of the two methods above. Prefer the venv PATH pattern first; if a special base image still blocks you, fall back to --break-system-packages.
Never do this
These two look convenient but will break your system.
sudo pip install ...: files managed by apt and files installed by pip collide on the same path. If apt then runs an update, dependencies can tangle andaptitself or system utilities may stop working.- Manually deleting the
EXTERNALLY-MANAGEDfile: pip will pass for now, but this permanently removes the safety mechanism. Later, when an OS update refreshes system Python packages, they can collide with pip-installed packages and the system Python can collapse.
Remember that both are the kind of fix that "looks like it works right now, then holds your entire system hostage later."
Conclusion — one-line recommendation by situation
- Project development →
python3 -m venv .venv(standard and safe) - CLI tools only →
pipx install <tool> - Speed matters →
uv venv+uv pip install - Docker/CI → dedicated venv in the image + PATH takeover
- Truly temporary / one-off →
pip install --user --break-system-packages
And once more: never run sudo pip install or delete the EXTERNALLY-MANAGED file. Spend 30 seconds picking your situation from the decision table, and you can install the packages you want safely while protecting the system.
In the next post, we will cover how to make the venv/uv environment you just created reproducible for the whole team — a practical workflow for pinning dependencies with pyproject.toml and lock files.
FAQ
Q. If I use --break-system-packages, will it actually break the system?
A. Using it once does not break things immediately. The risk appears when a pip-installed package collides with a same-named package managed by apt/brew. It is practical in a personal throwaway environment or Docker, but do not use it on the system Python of a production server.
Q. Should I use venv or pipx?
A. Use venv for libraries you import in code (requests, pandas, and so on). Use pipx when you only need command-line tools you run in the terminal, such as black or httpie. They are not mutually exclusive — you can use both depending on the situation.
Q. I just want it to work the old way. Can I delete the EXTERNALLY-MANAGED file?
A. Do not delete it. That permanently removes the safety mechanism, and the system Python can break on a later OS update. If you miss the old behavior, setting break-system-packages = true in pip.conf on a personal machine is the easier-to-revert option.
Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
Comments
Be the first to comment.