aio-libs/aiohttp · error · TypeError
Inheritance class {cls.__name__} from web.Application is for
Error message
Inheritance class {cls.__name__} from web.Application is forbidden What it means
Application.__init_subclass__ unconditionally raises TypeError for any subclass of aiohttp.web.Application. The framework intentionally treats Application as a composition root, not a base class — extending behavior is done via middlewares, signals, cleanup contexts, or AppKey state, never via inheritance. The message names the offending class ({cls.__name__}).
Source
Thrown at aiohttp/web_app.py:135
# initialized on freezing
self._run_middlewares: bool | None = None
self._state: dict[AppKey[Any] | str, object] = {}
self._frozen = False
self._pre_frozen = False
self._subapps: _Subapps = []
self._on_response_prepare: _RespPrepareSignal = Signal(self)
self._on_startup: _AppSignal = Signal(self)
self._on_shutdown: _AppSignal = Signal(self)
self._on_cleanup: _AppSignal = Signal(self)
self._cleanup_ctx = CleanupContext()
self._on_startup.append(self._cleanup_ctx._on_startup)
self._on_cleanup.append(self._cleanup_ctx._on_cleanup)
self._client_max_size = client_max_size
def __init_subclass__(cls: type["Application"]) -> None:
raise TypeError(
f"Inheritance class {cls.__name__} from web.Application is forbidden"
)
# MutableMapping API
def __eq__(self, other: object) -> bool:
return self is other
@overload # type: ignore[override]
def __getitem__(self, key: AppKey[_T]) -> _T: ...
@overload
def __getitem__(self, key: str) -> Any: ...
def __getitem__(self, key: str | AppKey[_T]) -> Any:
return self._state[key]
def _check_frozen(self) -> None:View on GitHub (pinned to c0ef574e29)
Solutions
- Do not subclass. Instantiate Application(middlewares=[...], client_max_size=..., ...) and use app[AppKey('k', T)] = v for state.
- Put cross-cutting concerns in a middleware factory or on_startup/on_cleanup signals.
- Use a wrapper class (composition) that owns an Application instance if you need a façade.
- For libraries, expose setup functions that mutate a passed-in Application rather than subclassing.
Example fix
// before
class MyApp(aiohttp.web.Application):
def __init__(self, *a, **kw):
super().__init__(*a, **kw)
self.db = Database()
// after
app = aiohttp.web.Application()
app[AppKey('db', Database)] = Database() Defensive patterns
Strategy: validation
Validate before calling
import aiohttp.web
def make_app(**overrides):
# composition, not inheritance
app = aiohttp.web.Application(**overrides)
return app Prevention
- Treat Application as final; extend via middlewares, signals, cleanup_ctx, AppKey state.
- Use a wrapper/ façade class if you need an app-like object.
- Lint against `class .*\(.*web\.Application\)` in CI.
When it happens
Trigger: Writing `class MyApp(aiohttp.web.Application): ...` anywhere in user code; libraries that historically subclassed Application to add attributes; copy-paste from another framework (Flask/Starlette) where subclassing the app is idiomatic.
Common situations: Migrating from Flask/FastAPI idioms; older aiohttp tutorials that predated the ban; libraries designed against aiohttp <3.x that subclass; adding per-app config attributes via subclass rather than via app['key'].
Related errors
- module {__name__} has no attribute {name}
- Inheritance class {cls} from ClientSession is forbidden
- Separator should be at least one-byte string
- Changing state of started or joined application is forbidden
- Prefix must be str
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/5ef21e76c60966af.json.
Report an issue: GitHub.