Textualize/textual · error · ScreenError

Can't await screen.dismiss() from the screen's message handl

Error message

Can't await screen.dismiss() from the screen's message handler; try removing the await keyword.

What it means

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.

Source

Thrown at src/textual/screen.py:2075

            call `self.dismiss()` _without_ awaiting.

        Args:
            result: The optional result to be passed to the result callback.

        """
        _rich_traceback_omit = True
        if self._result_callbacks:
            callback = self._result_callbacks[-1]
            callback(result)
        await_pop = self.app.pop_screen()

        def pre_await() -> None:
            """Called by the AwaitComplete object."""
            _rich_traceback_omit = True
            if active_message_pump.get() is self:
                from textual.app import ScreenError

                raise ScreenError(
                    "Can't await screen.dismiss() from the screen's message handler; try removing the await keyword."
                )

        await_pop.set_pre_await_callback(pre_await)

        return await_pop

    def pop_until_active(self) -> None:
        """Pop any screens on top of this one, until this screen is active.

        Raises:
            ScreenError: If this screen is not in the current mode.

        """
        from textual.app import ScreenError

        try:
            self.app._pop_to_screen(self)

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Remove the await: call self.dismiss(result) directly
  2. If you need post-dismiss logic, chain it via .call_after_refresh or a callback rather than awaiting dismissal
  3. Restructure so the caller awaits dismiss, not the screen itself

Example fix

# before
async def on_button_pressed(self, event) -> None:
    await self.dismiss(event.button.id)
# after
def on_button_pressed(self, event) -> None:
    self.dismiss(event.button.id)
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Writing 'await self.dismiss(result)' inside on_mount, event handlers, or actions of the same screen instance.

Common situations: 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.

Related errors


AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27). Data as JSON: /api/errors/9383abc6d09823b4. Report an issue: GitHub.