How to Fix "ModuleNotFoundError: No Module Named" in virtualenv / venv
Quick answer
You install a package with pip and it appears to succeed, but your script still can't find it. This almost always means the package was installed into a...
You install a package with pip and it appears to succeed, but your script still can't find it. This almost always means the package was installed into a different Python environment than the one actually running your script β a mismatch that's extremely common once virtual environments enter the picture.
The Problem
The install looks fine, but running the script fails immediately:
$ pip install requests
Successfully installed requests-2.32.3
$ python script.py
Traceback (most recent call last):
File "script.py", line 1, in <module>
import requests
ModuleNotFoundError: No module named 'requests'
Why It Happens
Every Python virtual environment has its own isolated set of installed packages, completely separate from the system Python and from any other virtualenv on the machine. A package installed while one environment is active is invisible to any other environment, including the plain system Python you'd get by typing python without any environment activated. This error appears when:
- The virtualenv wasn't actually activated when you ran
pip install, so the package went into the system Python (or a different environment) instead of the one your script uses. - The virtualenv was activated for the install but isn't active anymore when you run the script β for example, in a new terminal tab that starts fresh without the environment activated.
- Multiple Python installations exist on the machine (a system Python, a Homebrew Python, a pyenv-managed version), and
pipandpythonresolve to different ones depending onPATHordering. - An IDE or editor's "Run" button is configured to use a different Python interpreter than the terminal you used for the install.
The Fix
First, confirm whether your virtualenv is actually active β an active venv shows its name in the shell prompt, and you can verify explicitly:
which python
/usr/bin/python3 # <- this is the SYSTEM python, not a venv
If you expected a venv path like /home/user/myproject/venv/bin/python and instead see a system path, the environment isn't active. Activate it explicitly:
source venv/bin/activate
On Windows:
venv\Scripts\activate
Confirm activation worked:
which python
/home/user/myproject/venv/bin/python
Now install the package with the venv active, and it will land in the right place:
pip install requests
python script.py
To avoid this mismatch entirely, a more robust habit is invoking pip and python through the same explicit interpreter path rather than relying on activation and PATH resolution being correct in every terminal session:
./venv/bin/python -m pip install requests
./venv/bin/python script.py
Using python -m pip instead of a bare pip command guarantees the package installs into whichever Python that specific python command refers to, removing any ambiguity about which pip executable happened to be first on your PATH.
Still Not Working?
If activation looks correct and which python points at the venv, but the import still fails, double-check you're not accidentally running the script with a different interpreter than the one you tested with β this is common in editors and IDEs where the terminal and the "Run" button can be configured independently:
python -c "import sys; print(sys.executable)"
Compare this output against the interpreter path your editor is configured to use for running scripts (in VS Code, check the Python interpreter selector in the bottom status bar). If they differ, update your editor's configured interpreter to match the venv you've been installing packages into.
It's also worth understanding why venvs exist in the first place, since the isolation they provide is the whole point rather than an inconvenience to work around. Different projects often need different, sometimes conflicting, versions of the same package β one project might need an older version of a library for compatibility, while another needs the latest release for a new feature. Without virtual environments, installing packages globally (or with sudo pip install, which is worth avoiding entirely) means every project on the machine shares one single set of package versions, and upgrading a package for one project can silently break another that depended on the older behavior:
# A clean, deliberate workflow for every new project
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Getting into the habit of creating a fresh venv per project, and always double-checking it's active before running pip or python, eliminates this entire class of confusing "it worked yesterday" errors well before they have a chance to happen.