Textualize/textual · warning · WorkerCancelled
Worker was cancelled, and did not complete.
Error message
Worker was cancelled, and did not complete.
What it means
WorkerCancelled raised by Worker.wait(): the worker finished in CANCELLED state (its task was cancelled, e.g. via worker.cancel() or app shutdown), so there is no result to return. wait() re-raises cancellation to the awaiting caller instead of returning None.
Source
Thrown at src/textual/worker.py:454
"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:
raise WorkerCancelled("Worker was cancelled, and did not complete.")
return cast("ResultType", self._result)
View on GitHub (pinned to 06dbeef4bb)
Solutions
- Catch WorkerCancelled where cancellation is expected and treat it as a no-op: `except WorkerCancelled: pass`.
- Avoid awaiting workers that exclusive replacement may cancel, or re-check state afterwards.
- For cleanup-on-cancel, use try/finally inside the worker body.
Example fix
# before
result = await worker.wait()
# after
from textual.worker import WorkerCancelled
try:
result = await worker.wait()
except WorkerCancelled:
result = None Defensive patterns
Strategy: try-catch
Validate before calling
from textual.worker import WorkerState
if worker.state != WorkerState.CANCELLED:
result = await worker.wait() Try / catch
from textual.worker import WorkerCancelled
try:
result = await worker.wait()
except WorkerCancelled:
result = None Prevention
- Expect cancellation with exclusive=True workers
- Handle WorkerCancelled in every await of worker.wait()
- Do cleanup in try/finally inside the worker, not after wait()
When it happens
Trigger: `await worker.wait()` after `worker.cancel()` was called; cancellation triggered by exclusive workers (a new worker with exclusive=True cancels the previous one); or the app/screen shutting down cancels pending workers.
Common situations: Overlapping triggers of the same @work method with exclusive=True; awaiting a worker during app exit; user retriggers a search/load before the previous finished.
Related errors
- Can not create a worker from a non-async function unless `th
- Request to run a non-async function as an async worker
- Unsupported attempt to run an async worker
- Can't call worker.wait from within the worker function!
- Worker must be started before calling this method.
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/39e1ecd69389c850.
Report an issue: GitHub.