aio-libs/aiohttp · error · AttributeError
module has no attribute
Error message
module {__name__} has no attribute {name} What it means
aiohttp uses a PEP 562 module-level `__getattr__` for lazy imports. Only `GunicornUVLoopWebWorker` and `GunicornWebWorker` are special-cased (loaded on demand, returning `None` if gunicorn is absent). Every other attribute that is not already bound on the package raises `AttributeError`, meaning the requested name is not part of aiohttp's public API.
Solutions
- Check `aiohttp.__all__` (or the installed version's docs) for the correct public name.
- Import the symbol from its real submodule, e.g. `from aiohttp import web` or `from aiohttp.web import Application`.
- Pin the aiohttp version your code was written against so removed symbols don't surprise you.
Example fix
// before import aiohttp loop = aiohttp.AsyncccResolver() # typo / removed name -> AttributeError // after import aiohttp loop = aiohttp.ThreadedResolver() # valid exported name
Defensive patterns
Strategy: validation
Validate before calling
import aiohttp
name = "Application"
assert name in aiohttp.__all__ or hasattr(aiohttp, name), f"{name} is not exported by aiohttp" Try / catch
try:
obj = aiohttp.SomeName
except AttributeError:
# fall back to the correct submodule import
from aiohttp.web import Application as obj Prevention
- Treat `AttributeError` on the top-level package as an API-migration signal, not a runtime quirk.
- After upgrading aiohttp, run a static import check (`python -c 'import aiohttp'` plus mypy) before deploying.
- Prefer explicit submodule imports over reaching into the package root.
When it happens
Trigger: Any expression of the form `aiohttp.<name>` where `<name>` is neither an imported symbol in `aiohttp/__init__.py` nor one of the two lazy gunicorn worker names. Hits when the name was removed/renamed, is misspelled, or belongs to a private submodule that must be imported directly.
Common situations: Upgrading aiohttp (3.x to 4.x) where symbols moved or were removed; copy-pasted snippets referencing old names; IDE autocomplete suggesting a non-exported name; accessing a submodule class via the top package instead of `from aiohttp import web`.
Related errors
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/7c24bf80a055006a.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/__init__.py:258
def __dir__() -> tuple[str, ...]:
return __all__ + ("__doc__",)
def __getattr__(name: str) -> object:
global GunicornUVLoopWebWorker, GunicornWebWorker
# Importing gunicorn takes a long time (>100ms), so only import if actually needed.
if name in ("GunicornUVLoopWebWorker", "GunicornWebWorker"):
try:
from .worker import GunicornUVLoopWebWorker as guv, GunicornWebWorker as gw
except ImportError:
return None
GunicornUVLoopWebWorker = guv # type: ignore[misc]
GunicornWebWorker = gw # type: ignore[misc]
return guv if name == "GunicornUVLoopWebWorker" else gw
raise AttributeError(f"module {__name__} has no attribute {name}")
View on GitHub (pinned to d041d4d0fd)