{"record":{"id":"d6924c609b21687c","repo":"Textualize/textual","slug":"can-t-call-worker-wait-from-within-the-worker-func","errorCode":null,"errorMessage":"Can't call worker.wait from within the worker function!","messagePattern":"Can't call worker\\.wait from within the worker function!","errorType":"exception","errorClass":"DeadlockError","httpStatus":null,"severity":"error","filePath":"src/textual/worker.py","lineNumber":435,"sourceCode":"        \"\"\"Cancel the task.\"\"\"\n        self._cancelled = True\n        if self._task is not None:\n            self._task.cancel()\n        self.cancelled_event.set()\n\n    async def wait(self) -> ResultType:\n        \"\"\"Wait for the work to complete.\n\n        Raises:\n            WorkerFailed: If the Worker raised an exception.\n            WorkerCancelled: If the Worker was cancelled before it completed.\n\n        Returns:\n            The return value of the work.\n        \"\"\"\n        try:\n            if active_worker.get() is self:\n                raise DeadlockError(\n                    \"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:","sourceCodeStart":417,"sourceCodeEnd":453,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/worker.py#L417-L453","documentation":"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.","triggerScenarios":"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().","commonSituations":"Worker code that wants to 'join' another worker but grabs the current worker instead; refactoring app-level wait logic into the worker body.","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."],"exampleFix":"# before\n@work\nasync def do_work(self):\n    await self.get_current_worker().wait()  # deadlock\n# after\n@work\nasync def do_work(self):\n    await asyncio.sleep(1)  # just do the work","handlingStrategy":"validation","validationCode":"from textual.worker import get_current_worker, NoActiveWorker\ntry:\n    me = get_current_worker()\nexcept NoActiveWorker:\n    me = None\nif me is not target_worker:\n    await target_worker.wait()","typeGuard":null,"tryCatchPattern":"from textual.worker import DeadlockError\ntry:\n    await worker.wait()\nexcept DeadlockError:\n    pass","preventionTips":["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"],"tags":["worker","deadlock","async","textual"],"backgroundTag":"worker-self-deadlock","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}