/개발/How to Fix the pip externally-managed-environment Error (PEP 668)
Developmentexternally-managed-environmentPEP668

How to Fix the pip externally-managed-environment Error (PEP 668)

A practical guide to why pip install raises error: externally-managed-environment (PEP 668) and how to fix it by situation. Use the decision table to pick the right command among venv, pipx, uv, and --break-system-packages.

How to Fix the pip externally-managed-environment Error (PEP 668)

"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.

TEXT
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:

EnvironmentWhen it started
Ubuntu23.04 and later (including 23.10, 24.04 LTS)
Debian12 (bookworm) and later
FedoraApplied in recent releases
Homebrew PythonEnabled 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 situationRecommended fixWhy
You want it as a system-wide libraryapt install python3-<package> or a venvThe apt version is safe and will not collide with system tools
It is for developing a specific projectvenvPer-project isolation and reproducibility (the most standard approach)
You only want CLI tools such as black/httpiepipxAutomatic isolation per tool, PATH registration included
You are inside Docker/CIvenv, or a controlled --break-system-packagesThrowaway, isolated environment, so contamination risk is low
You want a fast, modern dev environmentuvRust-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.

Bash
python3 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install requests

Expected 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/activate every 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.

Bash
sudo apt install pipx      # 또는 brew install pipx
pipx ensurepath
pipx install httpie

After 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.

Bash
pip install --break-system-packages requests

Prefer combining it with --user so packages go into the user home (~/.local) instead of system directories — that is somewhat less risky.

Bash
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.

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.

INI
# ~/.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.

Bash
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv
uv pip install requests

uv 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.toml integration
  • Trade-off: learning cost of a new tool; you need team buy-in to adopt it org-wide

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.

Dockerfile
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.txt

Example requirements.txt:

TEXT
requests==2.32.3

If 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 and apt itself or system utilities may stop working.
  • Manually deleting the EXTERNALLY-MANAGED file: 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 developmentpython3 -m venv .venv (standard and safe)
  • CLI tools onlypipx install <tool>
  • Speed mattersuv venv + uv pip install
  • Docker/CI → dedicated venv in the image + PATH takeover
  • Truly temporary / one-offpip 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.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·
관련 공식 문서Python 공식 문서

Comments

Be the first to comment.