aio-libs/aiohttp · error · AttributeError
module {__name__} has no attribute {name}
Error message
module {__name__} has no attribute {name} What it means
Raised by the module-level __getattr__ in aiohttp/__init__.py when code accesses an attribute that is not part of the public API (__all__) and is not one of the lazily-imported gunicorn workers (GunicornUVLoopWebWorker, GunicornWebWorker). It is aiohttp's PEP 562 lazy-import fallback for unknown names. It almost always means a typo, a removed/renamed symbol, or code written against a different aiohttp version.
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 c0ef574e29)
Solutions
- Check aiohttp.__all__ (or dir(aiohttp)) for the exact public name you intended and fix the typo/rename.
- Import submodules directly from their real location, e.g. 'from aiohttp.http_websocket import WebSocketWriter' or 'from aiohttp._websocket.models import WSCloseCode', rather than reaching through the top-level package.
- If upgrading, consult the CHANGES/ folder and migration notes for renamed/removed symbols and update call sites.
- If you need the lazily-loaded gunicorn workers, ensure gunicorn is installed (the __getattr__ returns None on ImportError for those two names, so a different error appears).
Example fix
# before import aiohttp worker = aiohttp.GunicornSteamWorker # typo -> AttributeError # after import aiohttp worker = aiohttp.GunicornWebWorker # correct lazily-loaded name
Defensive patterns
Strategy: validation
Validate before calling
import aiohttp
name = 'GunicornWebWorker'
if name not in aiohttp.__all__ and name not in {'GunicornUVLoopWebWorker', 'GunicornWebWorker'}:
raise AttributeError(f'{name!r} is not a public aiohttp attribute')
obj = getattr(aiohttp, name) Prevention
- Import submodules from their real path instead of reaching through the top-level package.
- When upgrading aiohttp, grep your code for 'aiohttp.' usages and reconcile against aiohttp.__all__ and the CHANGES/ notes.
- Let your IDE/linter resolve names against the installed package so typos surface at edit time.
When it happens
Trigger: Any expression of the form aiohttp.<name> where <name> is not exported in aiohttp.__all__ and is not 'GunicornUVLoopWebWorker'/'GunicornWebWorker'. Common triggers: accessing a name that existed in aiohttp 3.x but was removed/moved in 4.x (e.g. relocated websocket helpers, renamed exceptions), or a typo like aiohttp.ClinetSession.
Common situations: Upgrading aiohttp across a major version (3.x -> 4.x) where symbols were reorganized; copy-pasting examples that import from the wrong path; relying on private helpers that live under aiohttp._websocket or aiohttp.http_websocket instead of the top-level package; static-analysis/IDE auto-complete picking a non-exported name.
Related errors
- Separator should be at least one-byte string
- Inheritance class {cls.__name__} from web.Application is for
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/7c24bf80a055006a.json.
Report an issue: GitHub.