The first thing every developer does when they see ModuleNotFoundError: No module named 'X' is run pip install X. That fixes the error about half the time. The other half, the pip install does nothing useful — sometimes because pip installs to a different Python than the one running, sometimes because the module is installed but Python is looking in the wrong place, sometimes because the import name is different from the package name, and sometimes because there is a virtual environment in the way. Five failure modes, one error message.
Table of contents
- Table of contents
- The direct answer
- Failure 1: the package is not installed for this Python
- Failure 2: pip is installing into a different Python than the one running
- Failure 3: the package name is different from the import name
- Failure 4: virtual environment mismatch
- Failure 5: the module is shadowed or on a bad PYTHONPATH
- The five-step diagnostic checklist
- FAQ
- FAQ
The honest short version: check which Python is running, check which Python pip is installing into, check the package name vs the import name, check for virtual environment mismatch, and check the PYTHONPATH. The error itself is a single line; the diagnosis is a five-step checklist.
Table of contents
- The direct answer
- Failure 1: the package is not installed for this Python
- Failure 2: pip is installing into a different Python than the one running
- Failure 3: the package name is different from the import name
- Failure 4: virtual environment mismatch
- Failure 5: the module is shadowed or on a bad PYTHONPATH
- The five-step diagnostic checklist
- FAQ
The direct answer
The five-step diagnostic, in order:
which python
# /usr/local/bin/python (or similar)
python --version
# Python 3.11.5
which pip
# /usr/local/bin/pip (or /path/to/venv/bin/pip)
pip show <package-name>
# Look for Name, Version, Location
If pip show says the package is installed but python -c "import <package-name>" still fails, the Python and the pip are looking at different sites. If pip show says the package is not installed, install it for the right Python: python -m pip install <package-name> (using -m pip guarantees the pip that runs belongs to the Python that runs).
If the package is installed and python -c "import <pkg>" works in the venv but fails outside, you have a virtual environment mismatch.
Failure 1: the package is not installed for this Python
The simplest case: the package is just not installed. You see:
ModuleNotFoundError: No module named 'requests'
pip install requests fixes it. Run python -m pip install requests instead of bare pip install requests to be safe — -m pip runs the pip module that belongs to the Python interpreter you are about to invoke.
The diagnostic that catches this:
python -m pip show requests
# Name: requests
# Version: 2.32.3
# Location: /usr/local/lib/python3.11/site-packages
If pip says the package is not installed, the answer is python -m pip install <name>. Done.
Failure 2: pip is installing into a different Python than the one running
The most common cause of “pip install did not fix it.” You have two Pythons on your machine — maybe python is 3.11 and python3 is 3.12, or python is the system Python and you also have a Homebrew Python. pip install installs to whichever Python pip belongs to. python script.py runs under whichever Python is on the PATH.
The diagnostic:
which python
# /usr/bin/python
which pip
# /usr/local/bin/pip
python -c "import sys; print(sys.executable)"
# /usr/bin/python
pip --version
# pip 24.0 from /usr/local/lib/python3.12/site-packages/pip (python 3.12)
Two different Python paths. You are installing to 3.12 but running on 3.11. The package will not be found.
The fix: always use python -m pip install <name>. The python here is the same one that will run your script, so python -m pip installs to the same site-packages that python script.py will look in.
Failure 3: the package name is different from the import name
A surprising number of Python packages have different install names and import names. The classic example:
$ pip install PyYAML
$ python -c "import yaml"
# Works
$ pip install python-dateutil
$ python -c "import dateutil"
# Works
But also:
$ pip install beautifulsoup4
$ python -c "import beautifulsoup4"
# Works
$ python -c "import bs4"
# Works (the import name is bs4, the install name is beautifulsoup4)
The diagnostic: check the install name on PyPI. Look at the project name vs the package name. PyPI shows both. Most packages have the same install and import name, but the ones that do not are the ones that bite you.
Common pairs:
| Install name | Import name |
|---|---|
PyYAML | yaml |
python-dateutil | dateutil |
beautifulsoup4 | bs4 |
scikit-learn | sklearn |
Pillow | PIL |
python-dotenv | dotenv |
opencv-python | cv2 |
pymongo | pymongo (matches) |
psycopg2-binary | psycopg2 |
ruamel.yaml | ruamel.yaml |
When the import name does not match the install name, pip install <install-name> is what you want. The error message tells you the import name; PyPI tells you the install name.
Failure 4: virtual environment mismatch
The second-most-common cause of “pip install did not fix it.” You are in a virtual environment, but the activation is not in effect for the script you are running, or the script is running in a different shell where the venv is not activated.
The diagnostic:
echo $VIRTUAL_ENV
# (empty — no venv active)
source .venv/bin/activate
echo $VIRTUAL_ENV
# /home/myboy/project/.venv
python -c "import requests"
# ModuleNotFoundError
You are in the venv shell, but you never pip installed requests into this venv. You installed it into your system Python before you created the venv.
The fix: install into the venv while it is active.
source .venv/bin/activate
python -m pip install requests
Or use the venv’s pip directly:
.venv/bin/pip install requests
.venv/bin/python script.py
The cardinal rule: always use python -m pip or <venv>/bin/pip, never bare pip. Bare pip resolves to whatever is on the PATH first, which is usually the system Python.
Failure 5: the module is shadowed or on a bad PYTHONPATH
The rarest but most painful cause. You have a file in your project named the same as a standard library module, or a PYTHONPATH environment variable is pointing Python at the wrong directory.
Example: you have a file called email.py in your project directory. You run python email.py. Python imports its own email.py instead of the standard library email module. You see ModuleNotFoundError: No module named 'email.mime' because Python is trying to import submodules of itself.
The diagnostic:
python -c "import email; print(email.__file__)"
# /home/myboy/project/email.py <-- this is your file, not the stdlib
If you see a project-local path, you have shadowing. Rename your file.
PYTHONPATH shadowing is similar: a PYTHONPATH env var pointing at an old directory that has a broken module. unset PYTHONPATH and see if the import works.
The five-step diagnostic checklist
The order matters — most fixes are caught at steps 1-3:
python -m pip show <package-name>— is it installed at all? If not, install it.python -c "import sys; print(sys.executable)"andpip --version— same Python? If not, usepython -m pip.- Check the import name vs the install name. PyPI shows both. Common mismatches: PyYAML, Pillow, beautifulsoup4.
- Check the venv.
echo $VIRTUAL_ENV— is the venv active? Did you install into the active venv? - Check for shadowing.
python -c "import <name>; print(<name>.__file__)"— does the path look right? If not, check for local file shadowing or PYTHONPATH.
If you reach step 5 without a fix, the issue is in your environment, not the package. Restart the shell, check the venv, and look for shell rc files that set PYTHONPATH.
For a deployed app that hits this error in production, the fix is the same as locally — pin the dependencies in requirements.txt or pyproject.toml, install them with the same Python that will run the app, and make sure the runtime image (Docker, serverless, managed platform) uses that exact Python. If you are deploying to a platform like RunxBuild’s backend services, the build step installs the deps from requirements.txt into the same Python that runs the app, and the build log shows the resolved versions. For what that pinned-Python runtime costs at production scale, the RunxBuild hosting calculator gives you the per-month number.
FAQ
Why does pip install X say “Requirement already satisfied” but Python still says “Module not found”?
You are installing into a different Python than the one running. Use python -m pip install X instead of pip install X. The python -m pip form guarantees the pip belongs to the Python that will run your script.
How do I find out which Python is running?
python -c "import sys; print(sys.executable)" prints the absolute path of the Python interpreter that is currently active. which python and which python3 show what is on the PATH.
Why does import X fail in my venv but work outside it?
The package is not installed in the venv. You installed it into your system Python before you created the venv. Activate the venv and pip install X again, or use python -m pip install X from inside the venv.
What is the difference between pip and pip3?
pip3 historically meant “the pip for Python 3” when both Python 2 and 3 were installed. On modern systems where Python 2 is gone, pip and pip3 usually point to the same thing. Always use python -m pip to be unambiguous.
How do I list all installed packages?
python -m pip list shows every package in the current Python’s site-packages. python -m pip freeze shows the same list in a format suitable for requirements.txt.
Why is the import name different from the install name?
The install name is the PyPI project name. The import name is the Python module name. Some packages intentionally use different names because the project name was already taken, or because the package was renamed. Check PyPI for the canonical install name.
What is PYTHONPATH and why does it matter?
PYTHONPATH is an environment variable that adds directories to Python’s module search path. If it is set to an old directory with a broken module, that directory shadows your installed packages. unset PYTHONPATH and try again.
Can a file in my project shadow a standard library module?
Yes. A file named email.py in your project directory shadows the stdlib email. Rename your file. The diagnostic is python -c "import email; print(email.__file__)" — if it shows a project-local path, you have shadowing.
FAQ
Why does pip install X say “Requirement already satisfied” but Python still says “Module not found”?
You are installing into a different Python than the one running. Use python -m pip install X.
How do I find out which Python is running?
python -c "import sys; print(sys.executable)" prints the absolute path of the Python interpreter that is currently active.
Why does import X fail in my venv but work outside it?
The package is not installed in the venv. Activate the venv and pip install X again, or use python -m pip install X from inside the venv.
What is the difference between pip and pip3?
On modern systems where Python 2 is gone, they point to the same thing. Always use python -m pip to be unambiguous.
How do I list all installed packages?
python -m pip list shows every package in the current Python’s site-packages. python -m pip freeze shows them in requirements.txt format.
Why is the import name different from the install name?
The install name is the PyPI project name. The import name is the Python module name. Some packages intentionally use different names. Check PyPI for the canonical install name.
What is PYTHONPATH and why does it matter?
PYTHONPATH is an env var that adds directories to Python’s module search path. If set to an old directory with a broken module, that directory shadows your installed packages.
Can a file in my project shadow a standard library module?
Yes. A file named email.py in your project directory shadows the stdlib email. Rename your file.