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

  1. Do not subclass. Instantiate Application(middlewares=[...], client_max_size=..., ...) and use app[AppKey('k', T)] = v for state.
  2. Put cross-cutting concerns in a middleware factory or on_startup/on_cleanup signals.
  3. Use a wrapper class (composition) that owns an Application instance if you need a façade.
  4. 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

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


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/5ef21e76c60966af.json. Report an issue: GitHub.