~/troubleshooting/modulenotfounderror-no-module-named-x-the-5-minute-python-fix
§ POST · MAY 17, 2026 v1.0

ModuleNotFoundError: No module named X – the 5-minute Python fix

ModuleNotFoundError almost always means one of five things. Check them in this order to fix the 'No module named X' error in under five minutes.
Ryan CallowayStaff contributor
  9 min read

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

  1. Does which python point inside your project’s .venv?
    • No → Cause 1 (activate the venv).
    • Yes → continue.
  2. 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.
  3. 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.
  4. Is the missing module your own code (not a third-party package)?
    • Yes → Cause 4 (editable install or python -m).
    • No → continue.
  5. Is there a file in your cwd named after the package?
    • Yes → Cause 5 (rename it, delete __pycache__).
    • No → continue.
  6. Are you in Jupyter or a VS Code notebook?
    • Yes → Cause 6 (!{sys.executable} -m pip install).
    • No → the Python install itself is broken; reinstall with uv or pyenv.

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

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.

esc