How to Fix ImportError and ModuleNotFoundError in Python
How do I fix ImportError and ModuleNotFoundError in Python?
TL;DR
- Bottom line:
ModuleNotFoundError(a subclass ofImportError) means Python cannot locate the module you're trying to import. The 5 most common causes: (1) package not installed (pip install), (2) wrong Python environment/virtualenv, (3) incorrectsys.path/ project structure, (4) circular imports between modules, (5) name shadowing (your file has the same name as a library). - Key tool/command:
python -c "import sys; print(sys.path)"shows exactly where Python looks for modules.pip show package_nameverifies installation location.python -m pip install packageensures you install into the correct Python. - Watch out for: Running
pip installoutside your virtualenv — the package goes into the system Python while your code runs in the venv. Always checkwhich python/where pythonfirst. Withuv, virtual environments do not includepipby default. - Works with: Python 3.6+ (ModuleNotFoundError introduced in 3.6). Applies to all
frameworks: Django, Flask, FastAPI, scripts, notebooks. Verified against Python 3.14 (released
Oct 7, 2025) — adds
-X importtime=2for tracking cached imports and REPL import auto-completion. [src9]
Constraints
- Always use
python -m pip installinstead of barepip install—pipmay point to a different Python interpreter thanpython, especially on systems with multiple Python versions. [src5] - Never hack
sys.path.insert()in application code — usepyproject.toml+pip install -e .for proper package resolution. sys.path hacks break when directory structure changes. [src1, src2] - Python 3.13+ deprecates
__package__and__cached__— setting these module attributes is deprecated and will cease to be set or considered by the import system in Python 3.15 (originally announced for 3.14 but slipped). Use__spec__.parentand__spec__.cachedinstead. [src8, src10] - uv-managed virtualenvs do not include pip — if using the
uvpackage manager, useuv pip installoruv addinstead of barepip. Only add pip when required for compatibility (e.g., Jupyter's%pipmagic). [src5] - Do not name files after stdlib modules — files named
random.py,email.py,test.py,json.py,os.pywill shadow the real stdlib module and causeImportError. Python 3.13 now warns about this explicitly. [src1, src8]
Quick Reference
| # | Cause | Likelihood | Signature | Fix |
|---|---|---|---|---|
| 1 | Package not installed | ~30% of cases | ModuleNotFoundError: No module named 'package' |
pip install package or python -m pip install package [src5]
|
| 2 | Wrong Python / virtualenv | ~20% of cases | pip install succeeds but import still fails |
Activate venv: source venv/bin/activate; verify: which python [src7] |
| 3 | Incorrect sys.path / project structure |
~15% of cases | ModuleNotFoundError for your own module |
Add __init__.py, fix project root, or use pip install -e . [src1, src2] |
| 4 | Circular import | ~10% of cases | ImportError: cannot import name 'X' from partially initialized module |
Refactor: move shared code to third module, or use local imports [src6] |
| 5 | Name shadowing (file shadows library) | ~8% of cases | ImportError: cannot import name 'X' from 'module' |
Rename your file (e.g., random.py -> my_random.py) [src1, src8]
|
| 6 | Relative import outside package | ~6% of cases | ImportError: attempted relative import with no known parent package |
Run as module: python -m package.module instead of
python module.py [src3, src4]
|
| 7 | Missing __init__.py |
~4% of cases | ModuleNotFoundError for subpackage |
Add empty __init__.py to directory [src1, src3] |
| 8 | Package name != import name | ~3% of cases | pip install succeeds, import name differs |
Check PyPI page for correct import name (e.g., pip install Pillow ->
import PIL) [src5]
|
| 9 | Python version mismatch | ~2% of cases | Package incompatible with Python version | Check package compatibility; use python --version [src5]
|
| 10 | IDE / editor path misconfiguration | ~2% of cases | Works in terminal but not in IDE | Set Python interpreter path in IDE settings [src2] |
Decision Tree
START
├── Is the module a third-party package (from PyPI)?
│ ├── YES -> Is it installed? (pip show package_name)
│ │ ├── NOT INSTALLED -> pip install package_name [src5]
│ │ └── INSTALLED -> Is it in the right environment?
│ │ ├── Check: which python / where python -> matches venv? [src7]
│ │ │ ├── WRONG PYTHON -> Activate correct venv [src7]
│ │ │ └── CORRECT PYTHON -> Does import name match package name?
│ │ │ ├── NO -> Find correct import name (PyPI docs) [src5]
│ │ │ └── YES -> Check for name shadowing [src8]
│ │ └── IDE using different interpreter? -> Set interpreter in IDE [src2]
│ └── NO -> It's your own module ↓
├── Does the error say "partially initialized module" or "circular import"?
│ ├── YES -> Circular import. Refactor or use local imports [src6]
│ └── NO ↓
├── Does the error say "relative import with no known parent package"?
│ ├── YES -> Run as module: python -m package.module [src3, src4]
│ └── NO ↓
├── Is the module in a subdirectory?
│ ├── YES -> Does the directory have __init__.py? [src1]
│ │ ├── NO -> Add __init__.py
│ │ └── YES -> Is the parent directory in sys.path? [src2]
│ └── NO ↓
├── Using uv? -> uv pip install or uv add (pip not available by default) [src5]
│ └── NO ↓
└── Print sys.path and verify module location
-> python -c "import sys; print('\n'.join(sys.path))" [src2]
Step-by-Step Guide
1. Read the exact error message
Python gives you precise information about what went wrong. Python 3.13+ provides even better error messages, including warnings when your file shadows a stdlib module. [src1, src8]
# ModuleNotFoundError — module doesn't exist in sys.path
ModuleNotFoundError: No module named 'requests'
# ImportError — module exists but the name inside it doesn't
ImportError: cannot import name 'Response' from 'my_module'
# ImportError — circular import
ImportError: cannot import name 'X' from partially initialized module 'Y'
# ImportError — relative import issue
ImportError: attempted relative import with no known parent package
# Python 3.13+ — name shadowing warning (new)
# "module 'random' has no attribute 'randint'" with hint:
# "consider renaming '/home/user/random.py'"
Verify: Note the exact module name and which pattern your error matches.
2. Check if the package is installed
For third-party packages, verify installation first. [src5]
# Check if installed and where
pip show requests
# SAFEST: use python -m pip to ensure correct Python
python -m pip install requests
# If using uv (pip not available by default)
uv pip install requests
# Or better: uv add requests
Verify: pip show package_name shows the package with a Location
inside your virtualenv's site-packages.
3. Verify you're in the right Python environment
The most frustrating cause: installing into system Python while running code in a virtualenv. [src7]
# Check which Python is active
which python # Linux/macOS
where python # Windows
# Activate virtualenv
source venv/bin/activate # Linux/macOS
.\venv\Scripts\Activate.ps1 # Windows PowerShell
# If using uv
uv venv
source .venv/bin/activate # Linux/macOS
# Verify after activation
python -c "import sys; print(sys.executable)"
Verify: sys.executable points to your virtualenv's Python binary.
4. Inspect sys.path
Python searches for modules in the directories listed in sys.path. [src1, src2]
# Print sys.path to see all search directories
import sys
print('\n'.join(sys.path))
# Check where an imported module actually comes from
import requests
print(requests.__file__)
Verify: The directory containing your module appears in sys.path.
5. Fix project structure
Proper Python package structure ensures imports work correctly. [src1, src3]
my_project/
├── pyproject.toml
├── src/
│ └── my_package/
│ ├── __init__.py # Makes it a package
│ ├── main.py
│ ├── utils.py
│ └── sub_package/
│ ├── __init__.py # Required for subpackage
│ └── helpers.py
├── tests/
│ ├── __init__.py
│ └── test_main.py
└── venv/
# For development: install your package in editable mode
pip install -e .
Verify: Run python -c "from my_package import main" from the project root.
6. Fix circular imports
Circular imports happen when module A imports from B and B imports from A. [src6]
# FIX 1: Move shared code to a third module
# shared.py (new)
class User: ...
# FIX 2: Use local (deferred) imports
def get_user_service():
from models import User # Import inside function
return User.objects.get(...)
# FIX 3: Import the module, not the name
import models # Instead of: from models import User
def get_user_service():
return models.User.objects.get(...)
Verify: python -c "import models; import services" works without errors.
7. Fix name shadowing
If your file has the same name as a library, Python imports your file instead. Python 3.13 now provides explicit warnings for this. [src1, src8]
# Check if you're shadowing a module
python -c "import random; print(random.__file__)"
# If it shows YOUR file -> NAME CONFLICT!
# Common offenders: random.py, email.py, test.py, json.py, os.py
# Fix: Rename your file, then clean cache
find . -name "__pycache__" -type d -exec rm -rf {} +
Verify: python -c "import random; print(random.__file__)" points to the stdlib.
Decision Logic
If error reads "No module named X" AND pip show X shows the package installed
--> Python interpreter mismatch. Run python -c "import sys; print(sys.executable)" to see the
active interpreter, then which pip (Linux/macOS) or where pip (Windows). Reinstall
with the explicit interpreter: python -m pip install X. [src5, src7]
If error reads "cannot import name 'X' from partially initialized module 'Y'"
--> Circular import. Either (1) extract X to a third shared module, (2) move the
from Y import X line inside the function that uses it, or (3) import Y and
reference Y.X at call time. Do NOT call importlib.reload() — it makes the cycle
worse. [src6]
If error reads "attempted relative import with no known parent package"
--> Script is being run as a top-level file, not a package. Run as a module:
python -m package.module from the project root, OR convert the relative import to absolute
(from package.helpers import X). [src3, src4]
If pip install succeeded but import still fails AND you're using uv
--> The uv-managed virtualenv has no pip by default — system pip installed into a different
environment. Activate the uv venv (source .venv/bin/activate) and reinstall with
uv pip install X or uv add X. [src5]
If the import works from the terminal but fails in Jupyter / VS Code / PyCharm
--> The IDE is using a different Python interpreter. Check sys.executable in a notebook cell
or IDE settings; point the IDE to the venv's Python (./venv/bin/python or
./.venv/bin/python). For Jupyter specifically, install ipykernel into the venv:
python -m ipykernel install --user --name myenv. [src2, src7]
If a third-party module imports fine but from module import X raises ImportError
--> Either (a) the package name differs from the import name (e.g. pip install Pillow ->
import PIL, pip install opencv-python -> import cv2,
pip install scikit-learn -> import sklearn), or (b) your local file shadows the
library — run python -c "import module; print(module.__file__)" and rename if it points into
your project. [src1, src5, src8]
If running on Python 3.13+ AND your custom import hook sets
module.__package__ or module.__cached__
--> Migrate now. Setting these attributes is deprecated in 3.13 and will be ignored in
Python 3.15 (the originally-announced 3.14 removal slipped). Set
module.__spec__.parent and module.__spec__.cached instead. Replace any
importlib.load_module() calls with exec_module(). [src8, src9, src10]
Code Examples
Robust import with fallback and diagnostics
# Input: Script needs to run in different environments
# Output: Graceful handling of missing imports with helpful error messages
import sys
import importlib
def safe_import(module_name, package_name=None, install_hint=None):
"""Try to import a module, providing helpful error if it fails."""
try:
return importlib.import_module(module_name)
except ImportError as e:
pkg = package_name or module_name
hint = install_hint or f"pip install {pkg}"
print(f"ERROR: Could not import '{module_name}'", file=sys.stderr)
print(f" Python executable: {sys.executable}", file=sys.stderr)
print(f" To fix: {hint}", file=sys.stderr)
raise SystemExit(1) from e
# Common packages where install name != import name
requests = safe_import('requests')
PIL = safe_import('PIL', package_name='Pillow')
cv2 = safe_import('cv2', package_name='opencv-python')
yaml = safe_import('yaml', package_name='PyYAML')
sklearn = safe_import('sklearn', package_name='scikit-learn')
Import debugging utility
# Input: Can't figure out why an import is failing
# Output: Diagnostic script that pinpoints the problem
import sys, os, importlib
def diagnose_import(module_name):
"""Diagnose why a module can't be imported."""
print(f"=== Import Diagnosis for '{module_name}' ===\n")
print(f"Python version: {sys.version}")
print(f"Executable: {sys.executable}")
print(f"Virtual env: {sys.prefix != sys.base_prefix}")
print(f"\nsys.path:")
for i, p in enumerate(sys.path):
exists = "OK" if os.path.exists(p) else "MISSING"
print(f" [{i}] {exists} {p}")
try:
mod = importlib.import_module(module_name)
print(f"\nImport succeeded!")
print(f" Location: {getattr(mod, '__file__', 'built-in')}")
return mod
except (ModuleNotFoundError, ImportError) as e:
print(f"\n{type(e).__name__}: {e}")
# Check for name shadowing
shadow = os.path.join(os.getcwd(), module_name.split('.')[0] + '.py')
if os.path.exists(shadow):
print(f"\nNAME SHADOWING: Found '{shadow}'!")
return None
if __name__ == '__main__':
diagnose_import(sys.argv[1] if len(sys.argv) > 1 else 'requests')
Proper package setup with pyproject.toml
# Input: Project where imports break from different directories
# Output: pyproject.toml that makes imports always work
[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.backends._legacy:_Backend"
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.9"
dependencies = [
"requests>=2.28",
"pydantic>=2.0",
]
[project.optional-dependencies]
dev = ["pytest>=7.0", "ruff>=0.1"]
[tool.setuptools.packages.find]
where = ["src"]
# Install in editable mode:
pip install -e ".[dev]"
# Now imports work from ANYWHERE
Anti-Patterns
Wrong: Installing packages globally
# BAD — installs into system Python, not your project's venv [src5, src7]
sudo pip install requests
pip install requests # Which Python? Who knows!
Correct: Use virtualenv and python -m pip
# GOOD — explicit, uses correct Python [src5, src7]
python -m venv venv
source venv/bin/activate
python -m pip install requests
Wrong: Hacking sys.path in application code
# BAD — fragile, breaks when directory structure changes [src2]
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'lib'))
from my_module import something
Correct: Proper package structure with editable install
# GOOD — works everywhere, no sys.path hacking [src1, src5]
pip install -e .
# Now: from my_package.my_module import something
Wrong: Running script directly with relative imports
# BAD — running directly breaks relative imports [src3, src4]
python my_package/utils.py
# Error: ImportError: attempted relative import with no known parent package
Correct: Run as module
# GOOD — Python knows the package context [src3, src4]
python -m my_package.utils
Common Pitfalls
pip installvspython -m pip install: Justpipmight point to a different Python thanpython. Always usepython -m pip installto guarantee you install into the Python you're actually running. [src5]- Package name != import name: Many packages have different pip and import names:
Pillow->PIL,opencv-python->cv2,beautifulsoup4->bs4,scikit-learn->sklearn,PyYAML->yaml. Check the PyPI page. [src5] - Missing
__init__.py: Python 3 has namespace packages (no__init__.pyneeded), but regular packages still need it for most use cases. Add an empty__init__.pyto every directory you want as a package. [src1, src3] - Name shadowing with
test.py: A file namedtest.pyshadows Python's built-intestmodule and can breakunittest. Other common shadows:email.py,random.py,json.py,string.py. Python 3.13 now warns about this explicitly. [src1, src8] - Stale
.pyc/__pycache__: After renaming or moving files, old bytecode cache may confuse imports. Delete withfind . -name "__pycache__" -exec rm -rf {} +. [src1] - Jupyter notebook path issues: Notebooks run from the notebook's directory, not your
project root. Add the project root:
sys.path.insert(0, '/path/to/project')or use%cd /path/to/project. [src2] - uv environments lack pip: If you created your virtualenv with
uv,pipis not installed by default. Useuv pip installoruv addinstead. Only add pip for Jupyter%pipcompatibility. [src5] - Python 3.13
__package__deprecation: Setting__package__or__cached__on a module is deprecated in 3.13 and will stop being respected by the import system in Python 3.15 (the originally-announced 3.14 removal slipped — they still work in 3.14 but emitDeprecationWarning). Use__spec__.parentand__spec__.cachedinstead. [src8, src9, src10] importlib.load_module()is deprecated (3.14+): Replace any custom loader code callingload_module()withexec_module(). Pending removal target is 3.15. [src9, src10]
Diagnostic Commands
# Check which Python is active
which python # Linux/macOS
where python # Windows
# Check if in virtualenv
python -c "import sys; print('venv' if sys.prefix != sys.base_prefix else 'system')"
# Print sys.path
python -c "import sys; print('\n'.join(sys.path))"
# Check if package is installed and where
pip show package_name
python -m pip show package_name
# Check where a module is loaded from
python -c "import module_name; print(module_name.__file__)"
# Find name shadowing
python -c "
import os, sys
stdlib = set(os.listdir(os.path.dirname(os.__file__)))
local = set(f for f in os.listdir('.') if f.endswith('.py'))
shadows = local & {s + '.py' for s in stdlib if not s.startswith('_')}
if shadows: print('Shadowing:', shadows)
else: print('No shadows found')
"
# Clean bytecode cache
find . -name "__pycache__" -type d -exec rm -rf {} +
find . -name "*.pyc" -delete
Version History & Compatibility
| Version | Behavior | Key Changes |
|---|---|---|
| Python 3.14 (Oct 2025) | ModuleNotFoundError (current) |
-X importtime=2 tracks cached imports (shows cached instead of
timings); REPL import auto-completion (import co<Tab>);
importlib.load_module() deprecated — use exec_module();
__package__/__cached__ removal slipped to Python 3.15 [src9, src10]
|
| Python 3.13 (Oct 2024) | ModuleNotFoundError (enhanced) |
Better name-shadowing warnings; __package__/__cached__ deprecated;
from .__future__ no longer triggers future statements [src8] |
| Python 3.12 | ModuleNotFoundError (standard) |
Improved error messages with suggestions for similar module names;
pkgutil.find_loader() deprecated [src1] |
| Python 3.11 | ModuleNotFoundError |
Exception groups; better tracebacks for import errors [src1] |
| Python 3.10 | ModuleNotFoundError |
importlib.metadata improvements; better error messages [src1] |
| Python 3.9 | ModuleNotFoundError |
importlib.resources updates [src1] |
| Python 3.6 | ModuleNotFoundError introduced |
New subclass of ImportError for missing modules [src1] |
| Python 3.3 | Namespace packages | __init__.py no longer required for namespace packages [src1] |
| Python 2.x | ImportError only |
No ModuleNotFoundError; different import semantics [src1] |
When to Use / When Not to Use
| Use When | Don't Use When | Use Instead |
|---|---|---|
Error says ModuleNotFoundError or ImportError |
Error is AttributeError after successful import |
Check the object name in the module |
import statement fails |
Error is SyntaxError in the imported module |
Fix syntax in the target module |
| Package installs but import still fails | Error is PermissionError during import |
Check file permissions |
| Error mentions "partially initialized module" | Error is ValueError from module code |
Debug the module's runtime logic |
| Module works in terminal but not in IDE | Error is DLL load failed or shared library missing |
Reinstall package with binary deps |
Important Caveats
ModuleNotFoundErroris a subclass ofImportError. CatchingImportErrorwill also catchModuleNotFoundError. Use the more specific type when you only want to handle missing modules.- Namespace packages (PEP 420, Python 3.3+) allow packages without
__init__.py, but only for specific use cases. For regular projects, always include__init__.py. pip install --userinstalls to~/.local/lib/pythonX.Y/site-packages/, which may not be insys.pathfor all Python invocations.- In Docker containers, you're usually running as root — there's no virtualenv needed. But with multi-stage builds, ensure packages are installed in the final stage.
importlib.reload(module)can re-import a module but won't fix circular imports — it may make them worse by re-triggering the import cycle.- Python 3.15 (upcoming) will stop respecting
__package__and__cached__module attributes — the originally-announced 3.14 removal slipped one release. Code that sets these during import will silently lose effect. Audit any custom import hooks and set__spec__.parent/__spec__.cachedinstead. [src10] - Python 3.14 (released Oct 7, 2025) keeps
__package__and__cached__working but emitsDeprecationWarning.importlib.load_module()is also deprecated in 3.14 — replace withexec_module(). [src9, src10] - Some packages broke compatibility with Python 3.14 early releases due to missing built-in modules (e.g., pandas wheels lagged). Always check package compatibility before upgrading Python — many issues resolve within a few months of a major release.