Skip to content
Latchkey

Python "cannot import name X from partially initialized module" (circular) in CI

Python began importing a module, hit an import back to a module still mid-initialization, and the requested name was not defined yet. The interpreter labels the module "partially initialized" and points at 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)". It reproduces deterministically based on import order.

python
ImportError: cannot import name 'User' from partially initialized module 'app.models'
(most likely due to a circular import) (/app/app/models/__init__.py)

Diagnose it: is it the build backend or a missing system library?

Python packaging failures in CI split into build-backend configuration problems and missing system headers. The traceback usually points at the backend even when the real cause is an absent -dev package.

Terminal
python -m pip install --upgrade pip build
python -m build --wheel 2>&1 | tail -40

# a compiler error naming a .h file is a system dependency, not a Python one
#   e.g. "Python.h: No such file" -> python3-dev
#        "openssl/ssl.h"          -> libssl-dev

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 needs a name from it.

A package __init__ eagerly imports submodules that import back

An __init__.py that imports everything can create a cycle when a submodule imports a name from the package root.

How to fix it

Defer the import to call time

Move the cross-import inside the function that needs it so the module is fully loaded before the name is accessed.

app/services.py
def get_user():
    from app.models import User  # imported lazily to break the cycle
    return User.query.first()

Restructure to remove the cycle

  1. Identify the two modules that import each other from the traceback.
  2. Extract the shared name into a third module both can import.
  3. Re-run so neither module depends on the other at load time.

How to prevent it

  • Avoid module-level imports between two interdependent modules.
  • Keep package __init__.py files thin to avoid eager cycles.
  • Move shared types into a leaf module both sides import.

Frequently asked questions

What causes Python "cannot import name X from partially initialized module" (circular) in CI?
There are 2 common causes: two modules import each other at module scope and a package __init__ eagerly imports submodules that import back. Module A imports B at the top, B imports A at the top; whichever loads first is incomplete when the other needs a name from it.
How do I fix Python "cannot import name X from partially initialized module" (circular) in CI?
There are 2 fixes depending on which cause you have: defer the import to call time and restructure to remove the cycle. Work through them in order, since the first is the most common.
What does Python "cannot import name X from partially initialized module" (circular) in CI actually mean?
An import fails with "ImportError: cannot import name 'X' from partially initialized module 'Y' (most likely due to a circular import)".
How do I stop Python "cannot import name X from partially initialized module" (circular) in CI happening again?
Avoid module-level imports between two interdependent modules. 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