What's actually happening here
You're running your Python script from the terminal and it works fine. Then you hit F5 in VS Code and get ModuleNotFoundError: No module named 'requests' — or whatever library you just installed. The debugger isn't using your virtual environment. It's using some other Python on your system, one that doesn't have your packages.
VS Code's debugger doesn't inherit your shell's PATH or the virtual environment you activated in the terminal. It uses the interpreter you've selected in the bottom-left corner of the status bar, or the one specified in launch.json. If either of those points to the wrong Python, you get this error. The fix is to make sure the debugger uses the exact same interpreter that your terminal uses.
Fix 1: The 30-second fix — select the right interpreter
Look at the bottom-left corner of VS Code's status bar. You should see something like Python 3.11.4 64-bit. Click it. A dropdown appears at the top with every Python interpreter VS Code can find. Pick the one that matches your virtual environment — it'll usually have the folder name in parentheses, like myproject or venv.
If you don't see it, click Enter interpreter path... and browse to the location manually. On Windows, that's .venv\Scripts\python.exe. On macOS or Linux, it's .venv/bin/python.
Once you've selected it, VS Code automatically updates .vscode/settings.json with a python.defaultInterpreterPath entry. The debugger reads this. Now hit F5. If the error's gone, you're done. Most of the time this fixes it.
Fix 2: The 5-minute fix — check launch.json
If the interpreter selection didn't help, the debug configuration might be overriding it. Open the Run and Debug view (Ctrl+Shift+D on Windows/Linux, Cmd+Shift+D on macOS). Click the gear icon to open launch.json. Look at the python configuration. If there's a pythonPath key, it's telling the debugger which Python to use — and that can override the selected interpreter.
Newer versions of VS Code use python instead of pythonPath, but the logic is the same. Here's what a typical config looks like:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
}
]
}
If you see a pythonPath or python line that points to a global Python, delete it or change it to point to your venv's executable. The cleanest approach is to just remove that line entirely so the debugger uses the selected interpreter. Then restart the debug session.
You can verify which interpreter the debugger actually uses by adding a quick print at the top of your script:
import sys
print(sys.executable)
Run it with the debugger. The output tells you the exact path. Compare it to the one your terminal shows with which python (or where python on Windows). If they differ, that's your problem.
Fix 3: The 15+ minute fix — clean the environment and settings
Sometimes the above isn't enough. You've selected the right interpreter, you've cleaned up launch.json, but the error persists. This usually means VS Code has cached the wrong interpreter, or your virtual environment itself is broken.
Step 1: Rebuild the virtual environment
If the venv was created with an older Python version or moved between machines, its paths can be stale. The fix is to recreate it from scratch. Delete the .venv folder (or whatever it's called), then create a new one:
# Windows
python -m venv .venv
.venv\Scripts\activate
# macOS/Linux
python3 -m venv .venv
source .venv/bin/activate
Reinstall your dependencies: pip install -r requirements.txt. This takes time, but it kills any subtle corruption. I've seen venvs where the pyvenv.cfg file pointed to a Python version that no longer existed, and the debugger silently fell back to something else.
Step 2: Wipe VS Code's Python-related caches and settings
VS Code stores interpreter selections per workspace in .vscode/settings.json. If you've changed things around, it might hold onto an old path. Open that file and check for python.defaultInterpreterPath. If it's there and points to a non-existent Python, fix it or remove it.
There's also a hidden cache in ~/.vscode/ (or %APPDATA%\Code on Windows) that stores the list of known interpreters. If you see a virtual environment listed twice with different paths, that's a sign of stale data. The nuclear option is to clear the Python extension's cache by uninstalling and reinstalling the Python extension. It's annoying but effective.
Step 3: Check for extension conflicts
If you're using the Pylance extension for intellisense, it sometimes interferes with debugger path resolution. Go to the Extensions view (Ctrl+Shift+X), find Pylance, and check if it's up to date. I've had one case where an old Pylance version forced the debugger to use a different interpreter, even though the selected one was correct. An update fixed it.
When this error actually shows up in the wild
You clone a repo from GitHub, run pip install -r requirements.txt in the terminal, then press F5. The debugger throws ModuleNotFoundError: No module named 'django' (or flask, or whatever). You check with the terminal and it's installed. This is the classic scenario. Another common one: you've been using a conda environment for weeks, then you switch to a venv, but VS Code still has the conda Python selected from a previous session.
The root cause, explained
The debugger doesn't source your shell profile. It spawns a fresh process with the interpreter you've pointed it to. If that interpreter isn't your venv, it won't see the packages installed in site-packages of that venv. It'll look at the global site-packages instead. That's why the error only appears when debugging — the terminal works because you activated the venv, which modified sys.path.
So the golden rule: the interpreter you select in VS Code must be the same one you use in your terminal. Check sys.executable in both, and if they match, the debugger will work. If they don't, fix it using the steps above. Start with the quick interpreter selection, then check launch.json, and only if both fail, go through the rebuild process.
I've seen people spend an afternoon debugging this, and the fix was literally a click on the status bar. Do that first.