Python's most common import failure looks like this:
Traceback (most recent call last):
File "<string>", line 1, in <module>
import nonexistent_pkg_xyz
ModuleNotFoundError: No module named 'nonexistent_pkg_xyz'
The message is narrower than it sounds. It does not mean the package is missing from your machine — it means the interpreter that just ran your code searched every directory on its sys.path and found nothing under that name. A package installed for a different Python, or sitting in a virtual environment you have not activated, produces exactly this error.
So the fix is almost never "install it again". It is "find out which interpreter is running, and whether the package is installed for that one":
python3 -c "import sys; print(sys.executable)"
python3 -m pip show <package>
If pip show reports nothing, install it with the same interpreter — note python3 -m pip, not a bare pip:
python3 -m pip install <package>
Why This Happens
There are five distinct causes, and they need different fixes. Work down them in order — this is roughly their real-world frequency.
| Cause | Tell |
|---|---|
| 1. Not installed for this interpreter | python3 -m pip show <pkg> finds nothing |
| 2. Installed for a different Python | pip3 show finds it, python3 -m pip show does not |
| 3. Virtual environment not active, or empty | sys.prefix == sys.base_prefix, or a fresh venv |
| 4. Import name differs from install name | pip show finds the package, import still fails |
5. Your own module is not on sys.path | The name is one of your own files, not a dependency |
Cause 1: Not Installed for This Interpreter
The base case. Install with the interpreter that failed:
python3 -m pip install requests
Always prefer python3 -m pip install over pip install. The -m form runs pip inside the interpreter you named, so the package cannot land anywhere that interpreter will not look. A bare pip is a separate executable on your PATH that may belong to an entirely different Python — which is cause 2, below, and the reason this error is so persistent.
If installing fails with error: externally-managed-environment, your Python is managed by the OS or Homebrew and is telling you to use a virtual environment instead. That is a separate error with its own fix.
Cause 2: Two Pythons, One PATH
The classic symptom is contradictory output: pip insists the package is installed, Python insists it is not.
which python3
which pip3
python3 -c "import sys; print(sys.executable)"
python3 -m pip --version
The last command prints both the pip version and the interpreter it belongs to:
pip 25.3 from /opt/homebrew/lib/python3.13/site-packages/pip (python 3.13)
If that path is not under the same prefix as sys.executable, they are different installations. On macOS this is routine — a python.org build, a Homebrew build, an Xcode command-line-tools build and a pyenv build can all be present at once.
The fix is not to remove Pythons. It is to stop using the bare pip command:
python3 -m pip install <package> # unambiguous
pip install <package> # ambiguous
Cause 3: Virtual Environment Not Active (or Freshly Created)
Check whether you are inside a venv at all:
python3 -c "import sys; print(sys.prefix != sys.base_prefix)"
True means you are in one, False means you are not. Activate it:
source .venv/bin/activate # macOS / Linux
.venv\Scripts\activate # Windows
A newly created venv is empty, which surprises people who expect it to inherit globally installed packages. It does not, deliberately — that isolation is the point. Reinstall your dependencies inside it:
python3 -m pip install -r requirements.txt
The same trap appears in Docker and CI: a RUN pip install in one layer and a venv activated in another do not necessarily refer to the same environment. Reference the venv's interpreter by absolute path in those cases:
RUN /opt/venv/bin/python -m pip install -r requirements.txt
Cause 4: The Import Name Is Not the Install Name
If pip show finds the package and the import still fails, you are probably importing the wrong name. Distribution names on PyPI and import names in Python are independent, and plenty of popular packages differ:
| You install | You import |
|---|---|
PyYAML | yaml |
beautifulsoup4 | bs4 |
Pillow | PIL |
opencv-python | cv2 |
python-dateutil | dateutil |
scikit-learn | sklearn |
python-dotenv | dotenv |
Django | django (lowercase) |
google-cloud-storage | google.cloud.storage |
If you are not sure what a package provides, ask pip:
python3 -m pip show -f <package> | head -20
The Files: section lists what was actually installed, and the top-level directory name there is the import name.
Cause 5: Your Own Module Is Not on sys.path
If the missing name is one of your own files, the problem is layout rather than installation. Python puts the directory of the script you ran at the front of sys.path — not your current working directory, and not the project root. So this fails:
myproject/
├── main.py # imports `from utils import helper`
└── src/
└── utils.py
Print the search path to see what Python is actually looking at:
python3 -c "import sys; print('\n'.join(sys.path))"
The durable fix is to run the code as a module from the project root, so the root is on the path:
python3 -m src.utils
Better still, make the project installable and install it in editable mode, which puts it on the path properly for every interpreter in the environment:
python3 -m pip install -e .
Avoid sys.path.append(...) at the top of your files. It works from one entry point and breaks from every other — including tests.
Verify the Fix
Confirm the import works with the exact interpreter that failed:
python3 -c "import requests; print(requests.__version__)"
And confirm it is coming from where you expect:
python3 -c "import requests; print(requests.__file__)"
Inside an active venv, that path should be under the venv directory:
/Users/you/project/.venv/lib/python3.13/site-packages/requests/__init__.py
If it points at a system path while a venv is active, the venv is not really active — check for a stale PYTHONPATH:
echo $PYTHONPATH
Prevention
- Use
python3 -m pipeverywhere, including in Dockerfiles, CI scripts and README instructions. It removes the entire class of interpreter-mismatch problems. - One virtual environment per project, created with
python3 -m venv .venvand activated before you install anything. - Pin dependencies in
requirements.txtorpyproject.tomlso a fresh environment can be rebuilt exactly. - Install your own project with
pip install -e .rather than manipulatingsys.path. - Print
sys.executablefirst when debugging. It answers "which Python is this?" in one line, and that is the question behind most occurrences of this error.