Textualize/textual · error · DeadlockError

Can't call worker.wait from within the worker function!

Error message

Can't call worker.wait from within the worker function!

What it means

DeadlockError from Worker.wait(): the worker attempted to await its own completion. wait() blocks until the worker finishes, so calling it from inside that worker's own function would wait forever; Textual detects this via the active_worker context and raises immediately.

Source

Thrown at src/textual/worker.py:435

        """Cancel the task."""
        self._cancelled = True
        if self._task is not None:
            self._task.cancel()
        self.cancelled_event.set()

    async def wait(self) -> ResultType:
        """Wait for the work to complete.

        Raises:
            WorkerFailed: If the Worker raised an exception.
            WorkerCancelled: If the Worker was cancelled before it completed.

        Returns:
            The return value of the work.
        """
        try:
            if active_worker.get() is self:
                raise DeadlockError(
                    "Can't call worker.wait from within the worker function!"
                )
        except LookupError:
            # Not in a worker
            pass

        if self.state == WorkerState.PENDING:
            raise WorkerError("Worker must be started before calling this method.")
        if self._task is not None:
            try:
                await self._task
            except asyncio.CancelledError as error:
                self.state = WorkerState.CANCELLED
                self._error = error
        if self.state == WorkerState.ERROR:
            assert self._error is not None
            raise WorkerFailed(self._error)
        elif self.state == WorkerState.CANCELLED:

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Remove the self-wait; just return/raise from the worker body.
  2. If waiting on a different worker, keep its reference (from run_worker return value) and await that, not get_current_worker().
  3. Move coordination to the caller: await worker.wait() from an event handler or on_mount.

Example fix

# before
@work
async def do_work(self):
    await self.get_current_worker().wait()  # deadlock
# after
@work
async def do_work(self):
    await asyncio.sleep(1)  # just do the work
Defensive patterns

Strategy: validation

Validate before calling

from textual.worker import get_current_worker, NoActiveWorker
try:
    me = get_current_worker()
except NoActiveWorker:
    me = None
if me is not target_worker:
    await target_worker.wait()

Try / catch

from textual.worker import DeadlockError
try:
    await worker.wait()
except DeadlockError:
    pass

Prevention

When it happens

Trigger: Inside a worker function (or @work method) calling `get_current_worker().wait()` or `self.wait()` on itself, including transitively through helpers that call worker.wait().

Common situations: Worker code that wants to 'join' another worker but grabs the current worker instead; refactoring app-level wait logic into the worker body.

Related errors


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