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
- Remove the self-wait; just return/raise from the worker body.
- If waiting on a different worker, keep its reference (from run_worker return value) and await that, not get_current_worker().
- 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
- Never await the current worker's wait()
- Await workers from handlers/on_mount, not inside worker bodies
- Store references returned by run_worker for joining later
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
- Can not create a worker from a non-async function unless `th
- Can't await screen.dismiss() from the screen's message handl
- Request to run a non-async function as an async worker
- Unsupported attempt to run an async worker
- Worker must be started before calling this method.
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/d6924c609b21687c.
Report an issue: GitHub.