Skip to content
Latchkey

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)

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.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →