{"record":{"id":"39e1ecd69389c850","repo":"Textualize/textual","slug":"worker-was-cancelled-and-did-not-complete","errorCode":null,"errorMessage":"Worker was cancelled, and did not complete.","messagePattern":"Worker was cancelled, and did not complete\\.","errorType":"exception","errorClass":"WorkerCancelled","httpStatus":null,"severity":"warning","filePath":"src/textual/worker.py","lineNumber":454,"sourceCode":"                    \"Can't call worker.wait from within the worker function!\"\n                )\n        except LookupError:\n            # Not in a worker\n            pass\n\n        if self.state == WorkerState.PENDING:\n            raise WorkerError(\"Worker must be started before calling this method.\")\n        if self._task is not None:\n            try:\n                await self._task\n            except asyncio.CancelledError as error:\n                self.state = WorkerState.CANCELLED\n                self._error = error\n        if self.state == WorkerState.ERROR:\n            assert self._error is not None\n            raise WorkerFailed(self._error)\n        elif self.state == WorkerState.CANCELLED:\n            raise WorkerCancelled(\"Worker was cancelled, and did not complete.\")\n        return cast(\"ResultType\", self._result)\n","sourceCodeStart":436,"sourceCodeEnd":456,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/worker.py#L436-L456","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"# before\nresult = await worker.wait()\n# after\nfrom textual.worker import WorkerCancelled\ntry:\n    result = await worker.wait()\nexcept WorkerCancelled:\n    result = None","handlingStrategy":"try-catch","validationCode":"from textual.worker import WorkerState\nif worker.state != WorkerState.CANCELLED:\n    result = await worker.wait()","typeGuard":null,"tryCatchPattern":"from textual.worker import WorkerCancelled\ntry:\n    result = await worker.wait()\nexcept WorkerCancelled:\n    result = None","preventionTips":["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()"],"tags":["worker","cancellation","async","textual"],"backgroundTag":"asyncio-task-cancelled","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}