{"record":{"id":"9383abc6d09823b4","repo":"Textualize/textual","slug":"can-t-await-screen-dismiss-from-the-screen-s-mes","errorCode":null,"errorMessage":"Can't await screen.dismiss() from the screen's message handler; try removing the await keyword.","messagePattern":"Can't await screen\\.dismiss\\(\\) from the screen's message handler; try removing the await keyword\\.","errorType":"exception","errorClass":"ScreenError","httpStatus":null,"severity":"error","filePath":"src/textual/screen.py","lineNumber":2075,"sourceCode":"            call `self.dismiss()` _without_ awaiting.\n\n        Args:\n            result: The optional result to be passed to the result callback.\n\n        \"\"\"\n        _rich_traceback_omit = True\n        if self._result_callbacks:\n            callback = self._result_callbacks[-1]\n            callback(result)\n        await_pop = self.app.pop_screen()\n\n        def pre_await() -> None:\n            \"\"\"Called by the AwaitComplete object.\"\"\"\n            _rich_traceback_omit = True\n            if active_message_pump.get() is self:\n                from textual.app import ScreenError\n\n                raise ScreenError(\n                    \"Can't await screen.dismiss() from the screen's message handler; try removing the await keyword.\"\n                )\n\n        await_pop.set_pre_await_callback(pre_await)\n\n        return await_pop\n\n    def pop_until_active(self) -> None:\n        \"\"\"Pop any screens on top of this one, until this screen is active.\n\n        Raises:\n            ScreenError: If this screen is not in the current mode.\n\n        \"\"\"\n        from textual.app import ScreenError\n\n        try:\n            self.app._pop_to_screen(self)","sourceCodeStart":2057,"sourceCodeEnd":2093,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/screen.py#L2057-L2093","documentation":"Textual forbids awaiting screen.dismiss() from within that screen's own message handler because it would require the screen to wait for its own removal, deadlocking the message pump. The check runs in a pre-await callback.","triggerScenarios":"Writing 'await self.dismiss(result)' inside on_mount, event handlers, or actions of the same screen instance.","commonSituations":"Dialog screens trying 'await self.dismiss(...)' after a button press instead of the non-awaited form; code migrated from older Textual versions where this was tolerated.","solutions":["Remove the await: call self.dismiss(result) directly","If you need post-dismiss logic, chain it via .call_after_refresh or a callback rather than awaiting dismissal","Restructure so the caller awaits dismiss, not the screen itself"],"exampleFix":"# before\nasync def on_button_pressed(self, event) -> None:\n    await self.dismiss(event.button.id)\n# after\ndef on_button_pressed(self, event) -> None:\n    self.dismiss(event.button.id)","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never await self.dismiss() inside the screen's own handlers","Chain post-dismiss work with call_later/worker callbacks"],"tags":["screen","dismiss","async","deadlock","textual"],"backgroundTag":"await-inside-own-handler","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}