Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Bash & Python Automation By James Joyner IV · · 10 min read

Bash & Python Error Guide: 'ModuleNotFoundError: No module named'

Fix Python ModuleNotFoundError: No module named: wrong interpreter, inactive venv, PYTHONPATH gaps, package vs import name mismatch, and sudo/cron context issues.

  • #automation
  • #troubleshooting
  • #errors
  • #python

Overview

ModuleNotFoundError: No module named '<name>' means the Python interpreter that is actually running could not find a top-level package or module named <name> on its import path. The error is rarely about whether the package “is installed” in the abstract — it is about whether it is installed for the specific interpreter executing your script, and whether your code’s location is on sys.path. The same machine can have several Pythons (system, venv, pyenv, conda), and a package installed into one is invisible to the others.

The standard traceback:

Traceback (most recent call last):
  File "/srv/app/main.py", line 3, in <module>
    import requests
ModuleNotFoundError: No module named 'requests'

It occurs at import time — usually immediately at the top of the script, but also lazily inside a function on first call. The most common contexts: a virtualenv that was never activated, running under sudo or cron with a different Python, a package whose import name differs from its pip name, and a local module that is not on sys.path because the script was launched from the wrong directory.

Symptoms

  • A traceback ending in ModuleNotFoundError: No module named '<name>'.
  • pip install <name> reports “already satisfied” but the import still fails.
  • It works in your terminal but fails under sudo, cron, systemd, or a different user.
  • It works from one directory but not another (local-module path issue).
python3 main.py
ModuleNotFoundError: No module named 'yaml'
pip install pyyaml
Requirement already satisfied: pyyaml in /home/ubuntu/.local/lib/python3.11/site-packages

(Installed for one Python; the script runs another.)

Common Root Causes

1. The package is installed for a different interpreter

You ran pip install against one Python but the script runs another (system python3 vs a venv vs python3.12).

which python3
python3 -c 'import sys; print(sys.executable)'
python3 -m pip show requests 2>&1 | head -3
/usr/bin/python3
/usr/bin/python3
WARNING: Package(s) not found: requests

Install for the same interpreter using -m pip:

python3 -m pip install requests

2. The virtualenv is not activated

The package lives in a venv, but the script ran with the system Python because the venv was never sourced (common in cron and CI).

echo "$VIRTUAL_ENV"
python3 -c 'import sys; print(sys.prefix)'

/usr

VIRTUAL_ENV is empty and sys.prefix is /usr, so the venv is inactive. Activate it or call its Python directly:

source /srv/app/.venv/bin/activate
# or, no activation needed:
/srv/app/.venv/bin/python main.py

3. The import name differs from the pip package name

Many packages install under a different import name. pip install PyYAML provides import yaml; beautifulsoup4 provides import bs4; python-dateutil provides import dateutil.

python3 -c 'import yaml' 2>&1
python3 -m pip show pyyaml | grep -i name
ModuleNotFoundError: No module named 'yaml'
Name: PyYAML

You installed (or need) PyYAML but the import is yaml. Install the correct distribution name, then import the correct module name.

4. The local module/package is not on sys.path

Importing your own module (import utils or from mypkg import x) fails because the directory containing it is not on sys.path — usually because you launched the script from elsewhere or it lacks an __init__.py for package imports.

cd /tmp && python3 /srv/app/main.py
ModuleNotFoundError: No module named 'utils'

Run as a module from the project root, or add the path:

cd /srv/app && python3 -m app.main
# or set it explicitly
PYTHONPATH=/srv/app python3 /srv/app/main.py

5. sudo / cron / systemd runs a different Python and environment

Under sudo, PATH, VIRTUAL_ENV, and PYTHONPATH are reset; cron and systemd have minimal environments. The interpreter resolved there has none of your user-installed packages.

which python3
sudo which python3
sudo python3 -c 'import requests' 2>&1
/srv/app/.venv/bin/python3
/usr/bin/python3
ModuleNotFoundError: No module named 'requests'

Use the venv’s absolute interpreter path in the privileged/scheduled context:

sudo /srv/app/.venv/bin/python3 main.py

6. A name shadowing or broken install

A local file named like a real package (e.g., your own email.py or queue.py) shadows the stdlib/third-party one, or a partial install left an importable-but-broken package.

ls *.py
python3 -c 'import requests; print(requests.__file__)'
requests.py  main.py
/srv/app/requests.py

Your requests.py shadows the real package. Rename it and delete any stale __pycache__.

Diagnostic Workflow

Step 1: Identify the exact interpreter running the script

python3 -c 'import sys; print(sys.executable); print(sys.prefix)'
head -1 ./main.py    # if invoked via ./main.py, the shebang decides

This is the Python that must have the package — everything else is downstream of this.

Step 2: Ask that interpreter what it can import and where it looks

python3 -m pip show <name>
python3 -c 'import sys; print("\n".join(sys.path))'

If pip show finds nothing under this interpreter, install with python3 -m pip install.

Step 3: Confirm the import name vs the package name

python3 -m pip list | grep -i <guess>
# e.g. yaml -> PyYAML, bs4 -> beautifulsoup4, cv2 -> opencv-python

Step 4: For local modules, verify the launch directory and path

python3 -c 'import sys; print(sys.path[0])'
ls -la <module>.py __init__.py 2>/dev/null

sys.path[0] is the script’s directory; the module must be reachable from there.

Step 5: Reproduce in the failing context (sudo/cron)

sudo -E python3 -c 'import sys; print(sys.executable)'
# In cron, add: python3 -c 'import sys; print(sys.executable)' >> /tmp/py.log

Example Root Cause Analysis

A data-sync script runs perfectly when an engineer runs it by hand but fails every night in cron:

Traceback (most recent call last):
  File "/srv/sync/run.py", line 2, in <module>
    import boto3
ModuleNotFoundError: No module named 'boto3'

Interactively, the engineer’s shell auto-activates a venv, so boto3 imports fine. Checking which interpreter each context uses:

which python3
/srv/sync/.venv/bin/python3
# What cron sees (logged from the job)
cat /tmp/py.log
/usr/bin/python3

Cron does not source the engineer’s ~/.bashrc, so the venv is never activated and the job runs the system /usr/bin/python3, which has no boto3. The package was only ever installed into the venv.

Fix: invoke the venv’s interpreter by absolute path in the crontab so no activation is needed:

# crontab entry
0 2 * * * /srv/sync/.venv/bin/python3 /srv/sync/run.py >> /var/log/sync.log 2>&1

The job now runs the interpreter that actually has boto3, and the nightly sync succeeds.

Prevention Best Practices

  • Always install with python3 -m pip install (not bare pip) so the package lands in the same interpreter you will run — eliminating the “installed for the wrong Python” class of failure.
  • In cron, systemd, and CI, reference the venv interpreter by absolute path (/srv/app/.venv/bin/python) rather than relying on shell activation that those contexts never perform.
  • Pin dependencies in requirements.txt and recreate the venv reproducibly; never mix sudo pip install (system) with user/venv installs.
  • Remember import-name vs pip-name differences (PyYAML/yaml, beautifulsoup4/bs4, opencv-python/cv2) and document them in your setup notes.
  • Avoid naming local files after real packages (requests.py, queue.py, email.py); such shadows produce confusing import errors.
  • For triaging tracebacks that surface in scheduled jobs, the free incident assistant can spot interpreter/venv mismatches from the log. More patterns in the Bash & Python automation guides.

Quick Command Reference

# Which interpreter is actually running?
python3 -c 'import sys; print(sys.executable, sys.prefix)'

# Is the package installed for THIS interpreter?
python3 -m pip show <name>

# Install for the same interpreter
python3 -m pip install <package>

# Inspect the import search path
python3 -c 'import sys; print("\n".join(sys.path))'

# Run a local package correctly
cd /project && python3 -m mypkg.main
PYTHONPATH=/project python3 /project/main.py

# Run the venv Python without activating
/srv/app/.venv/bin/python3 main.py

Conclusion

ModuleNotFoundError: No module named '<name>' means the interpreter that is running cannot find that package on its import path. The recurring causes:

  1. The package is installed for a different Python than the one executing.
  2. A virtualenv that was never activated (especially in cron/CI).
  3. The import name differs from the pip distribution name.
  4. A local module not on sys.path because of the launch directory.
  5. sudo/cron/systemd running a different interpreter with a stripped environment.
  6. A local file shadowing a real package, or a broken partial install.

Pin down the exact interpreter with sys.executable first, then make sure the package is installed for that interpreter with python3 -m pip — that single discipline resolves the large majority of these errors.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.