{"id":"4a19add5822f3e30","repo":"aio-libs/aiohttp","slug":"changing-state-of-started-or-joined-application-is","errorCode":null,"errorMessage":"Changing state of started or joined application is forbidden","messagePattern":"Changing state of started or joined application is forbidden","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_app.py","lineNumber":155,"sourceCode":"        )\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:\n        if self._frozen:\n            raise RuntimeError(\n                \"Changing state of started or joined application is forbidden\"\n            )\n\n    @overload  # type: ignore[override]\n    def __setitem__(self, key: AppKey[_T], value: _T) -> None: ...\n\n    @overload\n    def __setitem__(self, key: str, value: Any) -> None: ...\n\n    def __setitem__(self, key: str | AppKey[_T], value: Any) -> None:\n        self._check_frozen()\n        if not isinstance(key, AppKey):\n            warnings.warn(\n                \"It is recommended to use web.AppKey instances for keys.\\n\"\n                + \"https://docs.aiohttp.org/en/stable/web_advanced.html\"\n                + \"#application-s-config\",\n                category=NotAppKeyWarning,\n                stacklevel=2,","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_app.py#L137-L173","documentation":"Raised by Application._check_frozen when self._frozen is True. An application is frozen after AppRunner startup or after explicit freeze(); at that point the _state dict, middlewares, router, and signals are immutable because they are already in use by live request handling. Mutating app[key]=, del app[key], or adding routes after startup therefore aborts. The guard keeps running requests consistent with the configuration they were dispatched under.","triggerScenarios":"Setting `app['cache'] = ...` inside a request handler or on_startup-after-startup; adding routes from a background task after the runner started; mutating middleware list after run_app(); storing per-request state on the app instead of on the request.","commonSituations":"Lazy initialization done in the wrong lifecycle hook (should be on_startup, not in a handler); plugin systems that register routes dynamically; tests that reuse one app across multiple run_app() invocations; per-request caches accidentally written to app.","solutions":["Move initialization into an on_startup handler or cleanup_ctx, both fire before freeze takes effect.","Store per-request data on request['key'], not app['key'].","Register all routes and middlewares BEFORE run_app()/AppRunner.setup().","If you must reconfigure, rebuild a new Application rather than mutating a frozen one."],"exampleFix":"// before\nasync def handler(request):\n    request.app['db'] = Database()  # app frozen at request time\n    ...\n// after\nasync def init_db(app):\n    app['db'] = Database()\napp.on_startup.append(init_db)","handlingStrategy":"validation","validationCode":"def safe_set(app, key, value):\n    if getattr(app, '_frozen', False):\n        raise RuntimeError('app is frozen; set state in on_startup instead')\n    app[key] = value","typeGuard":null,"tryCatchPattern":"try:\n    app[key] = value\nexcept RuntimeError as e:\n    if 'started or joined' in str(e):\n        # defer to on_startup or move to per-request storage\n        ...\n    raise","preventionTips":["Set all app state in on_startup / cleanup_ctx, never in handlers.","Store per-request data on request, not app.","Register routes/middlewares before run_app()."],"tags":["web-app","lifecycle","state"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}