sqlalchemy/alembic · error · ImportError
Can't find Python file
Error message
Can't find Python file %s
What it means
Raised as ImportError by load_python_file when the requested .py file does not exist on disk and no compiled .pyc/.pyo fallback can be found (pyfiles.py:112-118). load_python_file is used to dynamically load env.py, custom env.py modules, and migration scripts. The function first checks for the .py file, then tries pyc_file_from_path for a bytecode fallback; if both fail, the ImportError is raised.
Solutions
- Verify the script_location path in alembic.ini/pyproject.toml points to the correct existing directory.
- Check that env.py exists: ls <script_location>/env.py.
- If the migrations directory was never created, run alembic init <directory> to scaffold it.
- Ensure you're running alembic from the correct working directory, or use absolute paths in the config.
- Check file permissions and case sensitivity (env.py, not Env.py or ENV.PY).
Example fix
# before: alembic.ini [alembic] script_location = ./migrations # directory doesn't exist # after [alembic] script_location = ./alembic # correct directory with env.py # or scaffold the directory alembic init alembic
Defensive patterns
Strategy: validation
Validate before calling
import os
def python_file_exists(directory, filename):
path = os.path.join(directory, filename)
if os.path.exists(path):
return True
# check for .pyc fallback
base, _ = os.path.splitext(path)
import importlib.machinery
for ext in importlib.machinery.BYTECODE_SUFFIXES:
if os.path.exists(base + ext):
return True
return False Try / catch
try:
module = load_python_file(dir_, filename)
except ImportError as e:
if "Can't find Python file" in str(e):
print(f"File not found: {os.path.join(dir_, filename)}")
print("Check script_location in your config and ensure env.py exists.")
raise Prevention
- Verify script_location in alembic.ini points to a real directory containing env.py.
- Run alembic from the project root so relative paths resolve correctly.
- Use absolute paths in config to avoid working-directory issues.
- Ensure 'alembic init' completed successfully before running other commands.
When it happens
Trigger: Calling load_python_file(dir_, filename) where dir_/filename doesn't exist and no .pyc sibling exists. Happens when Alembic's config points to a nonexistent env.py or when the script_location directory is wrong. Also triggered by 'alembic edit' or migration execution when the script file was deleted.
Common situations: Incorrect script_location in alembic.ini pointing to a non-existent migrations directory. env.py was accidentally deleted or never created (e.g., interrupted 'alembic init'). Running from the wrong working directory so relative paths don't resolve. Filesystem case sensitivity issues on Linux (Env.py vs env.py).
Related errors
- A plugin named is already registered
- Can not set dispatch function for object
- Can't change down_revision on a refresh operation.
- Can't drop table in batch mode
- Can't invoke function
AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11).
Data as JSON: /api/errors/f39bc862f9da397e.
Report an issue: GitHub.
Appendix: source
Thrown at alembic/util/pyfiles.py:118
def load_python_file(
dir_: str | os.PathLike[str], filename: str | os.PathLike[str]
) -> ModuleType:
"""Load a file from the given path as a Python module."""
dir_ = pathlib.Path(dir_)
filename_as_path = pathlib.Path(filename)
filename = filename_as_path.name
module_id = re.sub(r"\W", "_", filename)
path = dir_ / filename
ext = path.suffix
if ext == ".py":
if path.exists():
module = load_module_py(module_id, path)
else:
pyc_path = pyc_file_from_path(path)
if pyc_path is None:
raise ImportError("Can't find Python file %s" % path)
else:
module = load_module_py(module_id, pyc_path)
elif ext in (".pyc", ".pyo"):
module = load_module_py(module_id, path)
else:
assert False
return module
def load_module_py(module_id: str, path: str | os.PathLike[str]) -> ModuleType:
spec = importlib.util.spec_from_file_location(module_id, path)
assert spec
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) # type: ignore
return module
def _preserving_path_as_str(path: str | os.PathLike[str]) -> str:View on GitHub (pinned to 5551b5d35f)