Ch. 9 · Python

ModuleNotFoundError: No module named 'x' in Python

Fix ModuleNotFoundError: No module named 'x': installs into the wrong interpreter, inactive venvs, pip vs import names and python -m.

~8 min readbeginnerupdated Oct 4, 2026

The import fails and Python prints something like this (Python 3.14.7 on macOS; 3.12 and 3.13 print the same message, and paths are shortened here):

Traceback (most recent call last):
  File "~/demo/app.py", line 1, in <module>
    import requests
ModuleNotFoundError: No module named 'requests'
Text

It means the interpreter running right now searched every directory on its sys.path and found no module or package called requests. Usually the package is installed, just into a different Python.

A variant you will also see is No module named 'requests.adapters'; 'requests' is not a package, which points at a local file shadowing the real library (covered in Step 4).

Quick fix checklist

  • Print the interpreter that fails: python -c "import sys; print(sys.executable)", using the same command, terminal or IDE run button that raised the error.
  • Install with that exact interpreter: /path/from/above -m pip install requests. Prefer python -m pip to a bare pip.
  • Activate the project’s virtual environment (source .venv/bin/activate, or .venv\Scripts\activate on Windows) or select it as the interpreter in VS Code, PyCharm or Jupyter.
  • Check that you installed the right distribution name: cv2 needs opencv-python, PIL needs Pillow, sklearn needs scikit-learn, yaml needs PyYAML, bs4 needs beautifulsoup4.
  • For your own code, run from the project root with python -m mypackage.module instead of python mypackage/module.py.
  • Look for a local file or folder with the same name as the library (requests.py, random.py, numpy/) and rename it.

Before you start

You need a terminal and a basic idea of what a virtual environment is. If venvs are new to you, read Python virtual environments and reproducible dependencies first. Commands use macOS/Linux paths; on Windows, bin becomes Scripts. ModuleNotFoundError has existed since Python 3.6 as a subclass of ImportError, so except ImportError still catches it.

Why it happens

When Python executes import requests, it first checks the sys.modules cache. On a miss, it walks sys.path in order and asks each entry whether it contains requests.py or a requests/ package. sys.path is built per interpreter:

  1. sys.path[0]: the directory of the script you ran, or the current directory for python -m and python -c.
  2. Anything in the PYTHONPATH environment variable.
  3. The standard library of that interpreter.
  4. The site-packages directory of that interpreter or of the active virtual environment.

Item 4 is where most failures come from. A Homebrew Python, the system Python, a pyenv Python, a conda env and each venv all have separate site-packages directories. pip is just a script that installs into the site-packages of the Python it was launched with. If the pip on your PATH belongs to one Python and your editor runs another, the install succeeds and the import still fails.

Here are two interpreters on the same machine, one with requests and one without:

$ python3 -c "import sys; print(sys.executable); print(sys.prefix == sys.base_prefix)"
/opt/homebrew/opt/python@3.14/bin/python3.14
True
$ .venv/bin/python -c "import sys, requests; print(sys.executable); print(requests.__version__)"
~/demo/.venv/bin/python
2.34.2
Terminal

True for sys.prefix == sys.base_prefix means the first one is not a virtual environment.

Step-by-step walkthrough

Step 1: Identify the interpreter that raised the error

Run the diagnostic with the same launcher that failed. If the error came from an IDE’s Run button, put these lines at the top of the failing file temporarily:

import sys
print(sys.executable)
print(sys.prefix != sys.base_prefix)  # True inside a virtual environment
python

In a shell, also check what the bare commands resolve to, because python, python3 and pip can point at different installations:

which -a python python3 pip pip3   # Windows: where python
python3 -m pip --version           # pip X from <site-packages path> (python 3.x)
Terminal

The pip --version output names the site-packages directory it installs into. If that path is not under the interpreter from sys.executable, you have found the problem.

Step 2: Ask that interpreter whether the package is installed

$ python3 -m pip show requests
WARNING: Package(s) not found: requests
$ .venv/bin/python -m pip show requests | grep Location
Location: ~/demo/.venv/lib/python3.14/site-packages
Terminal

python -m pip guarantees that pip runs under the interpreter you named, so its answer is about the right site-packages. A bare pip show might be answering about a different Python entirely.

Step 3: Install into the right environment, or switch to it

Pick one of these, depending on what you intended:

# The project has a venv: activate it, then install and run inside it
source .venv/bin/activate
python -m pip install requests
python app.py

# No venv yet: create one (recommended)
python3 -m venv .venv
.venv/bin/python -m pip install requests
Terminal

In an IDE, choose the interpreter instead of installing again: in VS Code run “Python: Select Interpreter” and pick .venv/bin/python; in PyCharm set the project interpreter. In Jupyter, use %pip install requests in a cell, which installs into the kernel’s environment rather than whatever pip your shell finds.

Note

On Homebrew Python or Debian/Ubuntu’s system Python, python3 -m pip install outside a venv stops with error: externally-managed-environment. That is deliberate; see pip error: externally-managed-environment for the safe options.

Step 4: Check the import name and look for shadowing

The name you import and the name you pip install are not always the same, because PyPI distribution names and module names are independent:

Import Install
cv2 opencv-python
PIL Pillow
sklearn scikit-learn
yaml PyYAML
bs4 beautifulsoup4
dateutil python-dateutil

pip install cv2 and pip install PIL end in No matching distribution found, and pip install sklearn fails with a message pointing to scikit-learn. For installed packages, importlib.metadata.packages_distributions() maps import names back to distributions:

$ .venv/bin/python -c "import importlib.metadata as m; print(m.packages_distributions()['dateutil'])"
['python-dateutil']
Terminal

Shadowing is the other trap. Because sys.path[0] is the script’s own directory, a file named requests.py next to your script wins over the installed library. Importing a submodule then fails:

Traceback (most recent call last):
  File "~/demo/shadow/app2.py", line 1, in <module>
    from requests.adapters import HTTPAdapter
ModuleNotFoundError: No module named 'requests.adapters'; 'requests' is not a package
Text

'requests' is not a package is the giveaway: Python found something called requests, but it was a single file. Rename the local file and delete any __pycache__ next to it. For standard library names, Python 3.13 and newer add a hint such as consider renaming '.../random.py' since it has the same name as the standard library module named 'random' to the resulting AttributeError.

Worked scenario

A small project is laid out like this:

project/
  myapp/
    __init__.py
    util.py      # def slugify(s): ...
    cli.py       # from myapp.util import slugify
Text

The developer runs the CLI by path from the project root:

$ python3 myapp/cli.py
sys.path[0] = ~/demo/proj/myapp
Traceback (most recent call last):
  File "~/demo/proj/myapp/cli.py", line 3, in <module>
    from myapp.util import slugify
ModuleNotFoundError: No module named 'myapp'
Terminal

Diagnosis. A temporary print("sys.path[0] =", sys.path[0]) at the top of cli.py shows the cause. When you run a file by path, Python puts that file’s directory (project/myapp) at the front of sys.path, not the directory you are standing in. Inside project/myapp there is no myapp folder, so the absolute import fails. Switching to from .util import slugify just changes the error to ImportError: attempted relative import with no known parent package.

Fix. Run it as a module from the project root:

$ python3 -m myapp.cli
sys.path[0] = ~/demo/proj
hello-world
Terminal

With -m, sys.path[0] is the current directory (project/), and myapp.cli is imported as part of the myapp package, so both absolute and relative imports work. For a real tool, add a pyproject.toml with a console script entry point and install it with python -m pip install -e . inside the venv; the package is then importable from any directory.

Common mistake

The tempting fix is to paste this at the top of the file:

import sys, os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
python

It silences the error on your machine, but the import now depends on where the file lives on disk: tests, Docker images and teammates who run it differently break again, and you can import a stale copy from the wrong directory. Fix how the code is run (python -m, an editable install) instead of how it searches.

Also avoid sudo pip install (it writes into the OS Python and can break system tools) and reinstalling repeatedly with the same wrong pip.

Verify the behavior

Prove that the module now resolves from the environment you expect:

$ .venv/bin/python -c "import requests, sys; print(sys.executable); print(requests.__file__)"
~/demo/.venv/bin/python
~/demo/.venv/lib/python3.14/site-packages/requests/__init__.py
Terminal

Both paths should sit inside the same environment. If __file__ points at your project folder instead of site-packages, you are still shadowing the library. For the package case, python -m myapp.cli should run from the project root. A CI job that builds a fresh venv and runs the tests confirms nothing relies on a package installed only on your laptop.

Interview exercise

“A colleague ran pip install pandas, got Successfully installed, and the next line python app.py fails with ModuleNotFoundError: No module named 'pandas'. How do you debug it, and how do you prevent it?”

Answer and reasoning

The install succeeded, so the question is where. Python resolves imports by searching sys.path of the running interpreter, and pip installs into the site-packages of the interpreter it belongs to. I would compare the two: python -c "import sys; print(sys.executable)" against pip --version, which prints the target site-packages and its Python version. A mismatch (for example pip belonging to Python 3.12 and python resolving to 3.13, or a venv that is not activated) explains it.

The fix is to install with the interpreter that runs the code, python -m pip install pandas, ideally inside a project venv. Prevention: always use python -m pip, keep one venv per project, pin dependencies in pyproject.toml or a requirements file, and have CI build a fresh environment so a package that exists only on one laptop fails early. I would also rule out a local file shadowing the library.

Continue learning

Practise the import system with the Python interview questions and the Python MCQs. Related notes: Python virtual environments, import side effects and, if pip refuses to install at all, pip error: externally-managed-environment. Official references: The import system, the initialization of sys.path, the -m option and the Python Packaging Guide’s installing packages using pip and virtual environments.

More in Python

esc