Skip to content
LatchkeyLatchkey home

Python "cannot import name X from partially initialized module" (Circular)

Two modules import each other at load time, so when one is half-defined the other tries to use a name that does not exist yet. The "partially initialized module" wording is the unmistakable signature of a circular import.

What this error means

An import fails with ImportError: cannot import name X from partially initialized module Y (most likely due to a circular import), naming the file still being initialized. It is deterministic and tied to import order, not the network or environment.

Python traceback
ImportError: cannot import name 'db' from partially initialized module
'app.models' (most likely due to a circular import)
(/repo/app/models.py)

Diagnose it: which Python, and which index?

A pip failure in CI is usually about the interpreter or the index rather than the package. Runners have several Pythons installed, and the one on PATH is not necessarily the one your virtualenv or your workflow selected.

Terminal
which -a python python3 pip pip3
python -c "import sys; print(sys.executable, sys.version)"
pip config list
pip debug --verbose 2>/dev/null | grep -i "compatible tags" | head -5

Common causes

Two modules import each other at module scope

Module A imports B at the top, B imports A at the top. Whichever loads first is incomplete when the other reads from it, so the name is missing.

A shared object defined in a module that imports back

A common object (a db handle, config, app instance) lives in a module that also imports its consumers, creating a load-time cycle.

How to fix it

Move the shared symbol to a neutral module

Put the shared object in a third module that neither side imports back, then have both import from it.

Python
# app/extensions.py  (imports nothing from app)
db = Database()

# app/models.py and app/routes.py both:
from app.extensions import db

Defer the import inside the function

A local import runs after both modules are fully loaded, breaking the load-time cycle.

Python
def handler():
    from app.models import db   # imported lazily, not at module load
    ...

How to prevent it

  • Keep shared objects in a leaf module that imports nothing back.
  • Prefer dependency injection or lazy imports over import-time coupling.
  • Run the import graph in CI (e.g. import the package) to catch cycles.

Frequently asked questions

What causes Python "cannot import name X from partially initialized module" (Circular)?
There are 2 common causes: two modules import each other at module scope and a shared object defined in a module that imports back. Module A imports B at the top, B imports A at the top.
How do I fix Python "cannot import name X from partially initialized module" (Circular)?
There are 2 fixes depending on which cause you have: move the shared symbol to a neutral module and defer the import inside the function. Work through them in order, since the first is the most common.
What does Python "cannot import name X from partially initialized module" (Circular) actually mean?
An import fails with ImportError: cannot import name X from partially initialized module Y (most likely due to a circular import), naming the file still being initialized.
How do I stop Python "cannot import name X from partially initialized module" (Circular) happening again?
Keep shared objects in a leaf module that imports nothing back. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card