headroomlabs-ai/headroom · error · AttributeError

module {__name__!r} has no attribute {name!r}

Error message

module {__name__!r} has no attribute {name!r}

What it means

Raised by the headroom.providers package's module-level __getattr__ when code accesses an attribute that is not in the _LAZY_EXPORTS lazy-import table. The package defers importing heavy provider backends, so every public name must be declared in _LAZY_EXPORTS; anything else (a typo, a renamed symbol, or a private name that was never exported) falls through to this AttributeError, chained from the KeyError on the lookup dict.

Source

Thrown at headroom/providers/__init__.py:118

        "create_anyscale_provider",
    ),
    "create_vllm_provider": ("headroom.providers.openai_compatible", "create_vllm_provider"),
    "create_lmstudio_provider": (
        "headroom.providers.openai_compatible",
        "create_lmstudio_provider",
    ),
    "create_litellm_provider": ("headroom.providers.litellm", "create_litellm_provider"),
}


def __getattr__(name: str) -> object:
    if name == "__path__":
        raise AttributeError(name)

    try:
        module_name, attr_name = _LAZY_EXPORTS[name]
    except KeyError as exc:
        raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from exc

    module = import_module(module_name)
    value = getattr(module, attr_name)
    globals()[name] = value
    return value


def __dir__() -> list[str]:
    return sorted(set(globals()) | set(__all__))

View on GitHub (pinned to 322425c43b)

Solutions

  1. Check the spelling against _LAZY_EXPORTS / __all__ in headroom/providers/__init__.py and import the exact exported name
  2. Import from the concrete submodule instead: from headroom.providers.litellm import create_litellm_provider
  3. If the symbol was renamed in a release, migrate to the new name (see CHANGELOG.md)

Example fix

// before
from headroom.providers import create_litellm  # typo -> AttributeError

// after
from headroom.providers import create_litellm_provider
# or directly from the module:
from headroom.providers.litellm import create_litellm_provider
Defensive patterns

Strategy: validation

Validate before calling

import headroom.providers as hp

name = "create_litellm_provider"
if name not in dir(hp):  # __dir__ unions globals() with __all__
    raise ImportError(f"{name} is not exported by headroom.providers")
obj = getattr(hp, name)

Type guard

def is_lazy_export(name: str) -> bool:
    import headroom.providers as hp
    return name in hp.__all__

Try / catch

try:
    from headroom.providers import create_litellm_provider
except AttributeError as e:
    # fall back to the concrete submodule, which always works
    from headroom.providers.litellm import create_litellm_provider

Prevention

When it happens

Trigger: from headroom.providers import SomeName where SomeName is misspelled or was renamed between versions; getattr(headroom.providers, name) with a dynamically built name that is not in _LAZY_EXPORTS; accessing a symbol that exists in a submodule (e.g. headroom.providers.litellm) directly on the package without an export entry.

Common situations: Upgrading headroom after a provider symbol was renamed or removed; IDE autocompleting a symbol from a submodule onto the package root; copy-pasted import paths from older docs or examples.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/af83529a9b93ef2e. Report an issue: GitHub.