By Ryan Calloway. Updated May 2026.
ModuleNotFoundError: No module named 'X' is the single most common Python error on r/learnpython every week of the year. The fix is almost always one of five interpreter mismatches, and the diagnostic that picks the right one is two commands long. This post is the five-minute walk through them, in the order they fail.
Quick answer
In 95% of cases:
# 1. Confirm which Python you're running, and which one pip is targeting
which python && python -m pip --version
# 2. Install into THAT Python
python -m pip install <package-name>
If those two commands report the same interpreter and the install succeeds, your import will work on the next run. The other 5% are file-shadowing, name-mapping, project-layout, or notebook-kernel issues; the decision tree at the bottom of this post tells you which one in under a minute.
What ModuleNotFoundError actually means
Python looks up imports by walking sys.path — an ordered list of directories, plus the current working directory and any PYTHONPATH entries. ModuleNotFoundError: No module named 'X' means none of those directories contained an importable X. The error is honest. The reason is almost always not “the package is missing” but “the package is on disk somewhere Python is not looking”. Print sys.executable and sys.path and the wrong directory will be obvious.
python -c "import sys; print(sys.executable); print('\n'.join(sys.path))"
ModuleNotFoundError is a subclass of ImportError introduced in Python 3.6. Older codebases that catch ImportError still catch this; new code can be more specific.
The 30-second triage
Before you touch pip a second time, run these three commands and keep the output on screen.
which python # macOS / Linux
where.exe python # Windows
python --version
python -c "import sys; print(sys.executable)"
If which python does not point inside .venv/bin/python (or .venv\Scripts\python.exe on Windows) for your project, no virtual environment is active — start with Cause 1. If sys.executable prints a path different from where pip install dropped the package (run python -m pip show <pkg> and read the Location line), you have the split-Python problem — start with Cause 2. Everything else falls into Causes 3–5.
Cause 1: virtual environment not activated
Diagnosis. which python resolves to /usr/bin/python3, /opt/homebrew/bin/python3, or C:\Python313\python.exe — somewhere outside your project’s .venv. The package is installed into the wrong interpreter, or not installed at all into the venv you forgot to activate.
Fix.
# macOS / Linux
source .venv/bin/activate
which python # should end in .venv/bin/python
python -m pip install -r requirements.txt
# Windows PowerShell
.\.venv\Scripts\Activate.ps1
python -c "import sys; print(sys.executable)"
If your project has no .venv yet, set one up. The Python virtual environment guide has the 15-second setup, plus uv if you want something faster than stdlib venv. Fifteen seconds once beats forty minutes of PYTHONPATH debugging later.
Cause 2: pip and python point at different interpreters
Diagnosis. pip install requests prints “Successfully installed”, but python -c "import requests" still raises ModuleNotFoundError. pip --version and python -m pip --version report different paths.
The bare pip command resolves through your $PATH; if pyenv, Homebrew, conda, and a venv all claim the name, you can end up running a pip from one Python and a python from another. Installations and imports diverge silently.
Fix. Always use the python -m pip form. It guarantees the install lands inside the interpreter that will run your code.
python -m pip install requests
python -m pip show requests # confirm Location is inside your venv
The pip user guide recommends this form for the same reason. Adopt python -m pip as your default and this class of bug stops happening. If you have switched to uv, the equivalent is uv pip install or uv add; either targets the project’s environment correctly without the $PATH ambiguity.
Cause 3: PyPI name does not match the import name
Diagnosis. pip install pillow succeeds. import pillow raises ModuleNotFoundError: No module named 'pillow'. The package is installed; you are typing the wrong name.
Package names on PyPI do not always match what you type after import. The most common offenders:
pip install |
import |
|---|---|
| beautifulsoup4 | bs4 |
| pillow | PIL |
| python-dotenv | dotenv |
| pyyaml | yaml |
| opencv-python | cv2 |
| scikit-learn | sklearn |
| msgpack-python | msgpack |
| discord.py | discord |
| protobuf | google.protobuf |
Fix. Open the package’s PyPI page. The first code block in the README is the import name. When this error lands on r/learnpython, half the replies ask for the exact pip install command, for this reason.
Cause 4: your own package and the project-layout trap
Diagnosis. The missing module is something you wrote — from mypackage.utils import foo — not a third-party install. The traceback points at your own code, not site-packages. which python looks fine; pip show is not relevant because you never installed it.
Python cannot see your project root because you ran the file directly instead of as a module, or you launched from a subdirectory. sys.path[0] is the directory of the script you invoked, not the project root.
Fix — three options, ranked.
# Option A (best): editable install at the project root.
# One pyproject.toml plus this command and the import works from anywhere.
python -m pip install -e .
# Option B: run as a module instead of a file.
python -m mypackage.script # not: python mypackage/script.py
# Option C (last resort): export PYTHONPATH for the current shell.
export PYTHONPATH=$PWD # macOS / Linux
$env:PYTHONPATH = $PWD # Windows PowerShell
python mypackage/script.py
Option A is the long-term fix. A minimal pyproject.toml with [project] name and version is enough; pip install -e . drops a marker into site-packages that points back at your source tree, and the import resolves the same way third-party packages do. Stop typing sys.path.append; learn the editable install pattern once.
Cause 5: a local file is shadowing a stdlib or third-party module
Diagnosis. You named a file requests.py, random.py, email.py, token.py, json.py, csv.py, or http.py in your working directory. Python imports your file first because the cwd is at the front of sys.path. print(dir(requests)) returns a near-empty list, then requests.get fails with AttributeError: module 'requests' has no attribute 'get'. Same root cause as a bare ModuleNotFoundError.
A second symptom: a stale __pycache__/ entry. Even after you rename the offending file, Python may resolve the cached .pyc and produce the same error.
Fix.
# macOS / Linux
ls *.py | grep -E "^(requests|random|email|token|json|csv|http|test|string|copy)\.py$"
rm -rf __pycache__
# Windows PowerShell
Get-ChildItem -Filter *.py | Where-Object { $_.Name -match "^(requests|random|email|token|json|csv|http|test|string|copy)\.py$" }
Remove-Item -Recurse -Force __pycache__
Rename anything that prints. As a habit, never name a Python file after a stdlib module or a package you import. my_random.py reads worse but works.
Cause 6: Jupyter or VS Code notebook running a different kernel
Diagnosis. pip install requests works in the shell. The notebook cell still raises ModuleNotFoundError. The kernel and your terminal are running two different Pythons.
Fix. In the notebook, print which Python the kernel is using, then install into that exact interpreter.
import sys
print(sys.executable)
# Then, in a new cell:
import sys
!{sys.executable} -m pip install requests
The bang-prefix shell call combined with {sys.executable} is the only reliable pattern. Plain !pip install resolves through the shell’s $PATH and almost always picks the wrong Python on a multi-environment machine. The VS Code notebook docs document this as the supported approach. Tutorials that recommend bare !pip install pre-date 2023.
Decision tree: which fix is yours
- Does
which pythonpoint inside your project’s.venv?- No → Cause 1 (activate the venv).
- Yes → continue.
- Does
python -m pip show <pkg>succeed and show a Location inside that venv?- “WARNING: Package(s) not found” → Cause 2 (install with
python -m pip). - Location is outside the venv → Cause 2.
- Yes → continue.
- “WARNING: Package(s) not found” → Cause 2 (install with
- Is the import name on the package’s PyPI README the same as what you typed?
- No → Cause 3 (use the README’s import name).
- Yes → continue.
- Is the missing module your own code (not a third-party package)?
- Yes → Cause 4 (editable install or
python -m). - No → continue.
- Yes → Cause 4 (editable install or
- Is there a file in your cwd named after the package?
- Yes → Cause 5 (rename it, delete
__pycache__). - No → continue.
- Yes → Cause 5 (rename it, delete
- Are you in Jupyter or a VS Code notebook?
FAQ
Why does pip install succeed but the import still fail?
The pip on your $PATH is a different Python from the python on your $PATH. Force the same one with python -m pip install <pkg>. That is Cause 2 and it covers roughly a third of the questions on r/learnpython.
Do I need a virtual environment for a one-file script?
Yes. Since PEP 668 shipped in 2023, system Python on Debian, Ubuntu, and Homebrew refuses bare pip install by default with an “externally-managed-environment” error. python -m venv .venv && source .venv/bin/activate takes 15 seconds. Skipping it costs more time than it saves, every time.
Why does the same script work in PyCharm but fail in the terminal?
PyCharm adds the project root to PYTHONPATH automatically. Your terminal does not. Either run with python -m mypackage.script from the project root, or do an editable install (pip install -e .) and the difference disappears.
Is sys.path.append() a good fix?
For a quick experiment in a REPL, fine. For code you will commit, no. It silently breaks when you move the file or rename a folder, and the failure looks identical to the original ModuleNotFoundError with no clue that sys.path.append is the cause. Use an editable install instead.
My package is installed but VS Code still underlines the import in red.
Your IDE is using a different interpreter from your shell. Open the Command Palette, run “Python: Select Interpreter”, point it at .venv/bin/python. Save and the underline disappears. Pin the interpreter in .vscode/settings.json at the workspace level so teammates do not have to repeat the dance.
How do I confirm where a package was installed?
python -m pip show <pkg> and read the Location line. That directory must appear in sys.path. If it does not, you have Cause 2.
What about conda activate instead of source activate?
If you are on conda, conda activate <env> replaces both venv activation and the interpreter switch. Same diagnosis applies: which python after activation should point inside the conda env directory. If it does not, the env did not activate cleanly; check your shell init for stale conda init blocks.
Sources and further reading
- Python
ModuleNotFoundErrorreference - Python import system reference — how
sys.path, packages, and finders fit together - Python
sys.pathinitialization — what gets added and in what order - pip user guide: using pip from your program — the
python -m piprecommendation - PEP 668 — Marking Python base environments as externally-managed
- PEP 660 — Editable installs for pyproject.toml-based builds
- uv documentation — modern alternative that sidesteps most pip-vs-python ambiguity
If this error keeps catching you, the gap is usually in your venv workflow. The Python virtual environment guide covers the 15-second setup including uv. For the next layer up — what to do once your imports work and you start writing real code — the list comprehension examples and the dictionary methods guide are the two most-reached-for daily-driver references.