{"record":{"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/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/web_app.py#L137-L173","documentation":"Raised by Application._check_frozen (invoked from __setitem__ and other state mutators) when code tries to change application state after the app has been frozen. An Application is frozen during startup (and when added as a subapp), because mutating state concurrently with request handling is unsafe. This enforces immutability of the application object once the server is live.","triggerScenarios":"Calling app['key'] = value (or other state-changing operations) inside a request handler, an on_startup handler that runs after freeze, or after web.run_app has started serving.","commonSituations":"Lazily initializing shared resources in a handler instead of on_startup; trying to register routes or middlewares after startup; mutating app state from a background task spawned during serving.","solutions":["Perform all state setup in an on_startup handler or cleanup_ctx before the app starts serving.","For per-request mutable state, use request['key'] (the Request storage) instead of app['key'].","If you need shared mutable runtime state, store a mutable container (dict/obj) once at startup and mutate its contents, not the app mapping."],"exampleFix":"# before\nasync def handler(request):\n    request.app['cache'] = {}  # raises once frozen\n\n# after\nasync def init_cache(app):\n    app['cache'] = {}\napp.on_startup.append(init_cache)\n# handlers then read app['cache'] and mutate its contents","handlingStrategy":"validation","validationCode":"if app.frozen:\n    raise RuntimeError('cannot mutate app after startup; use on_startup')\napp['key'] = value","typeGuard":"def app_writable(app) -> bool:\n    return not getattr(app, 'frozen', False)","tryCatchPattern":"try:\n    app['key'] = value\nexcept RuntimeError as e:\n    if 'frozen' in str(e).lower() or 'forbidden' in str(e):\n        # defer to a mutable container set up at startup\n        app['runtime']['key'] = value\n    else:\n        raise","preventionTips":["Set all application state in on_startup or cleanup_ctx, never in handlers.","Store mutable containers at startup and mutate their contents at runtime.","Use request['key'] for per-request state."],"tags":["web","application","lifecycle","state"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}