{"id":"5ef21e76c60966af","repo":"aio-libs/aiohttp","slug":"inheritance-class-cls-name-from-web-applicat","errorCode":null,"errorMessage":"Inheritance class {cls.__name__} from web.Application is forbidden","messagePattern":"Inheritance class (.+?) from web\\.Application is forbidden","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_app.py","lineNumber":135,"sourceCode":"        # initialized on freezing\n        self._run_middlewares: bool | None = None\n\n        self._state: dict[AppKey[Any] | str, object] = {}\n        self._frozen = False\n        self._pre_frozen = False\n        self._subapps: _Subapps = []\n\n        self._on_response_prepare: _RespPrepareSignal = Signal(self)\n        self._on_startup: _AppSignal = Signal(self)\n        self._on_shutdown: _AppSignal = Signal(self)\n        self._on_cleanup: _AppSignal = Signal(self)\n        self._cleanup_ctx = CleanupContext()\n        self._on_startup.append(self._cleanup_ctx._on_startup)\n        self._on_cleanup.append(self._cleanup_ctx._on_cleanup)\n        self._client_max_size = client_max_size\n\n    def __init_subclass__(cls: type[\"Application\"]) -> None:\n        raise TypeError(\n            f\"Inheritance class {cls.__name__} from web.Application is forbidden\"\n        )\n\n    # MutableMapping API\n\n    def __eq__(self, other: object) -> bool:\n        return self is other\n\n    @overload  # type: ignore[override]\n    def __getitem__(self, key: AppKey[_T]) -> _T: ...\n\n    @overload\n    def __getitem__(self, key: str) -> Any: ...\n\n    def __getitem__(self, key: str | AppKey[_T]) -> Any:\n        return self._state[key]\n\n    def _check_frozen(self) -> None:","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_app.py#L117-L153","documentation":"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__}).","triggerScenarios":"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.","commonSituations":"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'].","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."],"exampleFix":"// before\nclass MyApp(aiohttp.web.Application):\n    def __init__(self, *a, **kw):\n        super().__init__(*a, **kw)\n        self.db = Database()\n// after\napp = aiohttp.web.Application()\napp[AppKey('db', Database)] = Database()","handlingStrategy":"validation","validationCode":"import aiohttp.web\n\ndef make_app(**overrides):\n    # composition, not inheritance\n    app = aiohttp.web.Application(**overrides)\n    return app","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["web-app","api","design"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}