{"record":{"id":"3b7b94f6487d31a4","repo":"Textualize/textual","slug":"unsupported-attempt-to-run-a-thread-worker","errorCode":null,"errorMessage":"Unsupported attempt to run a thread worker","messagePattern":"Unsupported attempt to run a thread worker","errorType":"exception","errorClass":"WorkerError","httpStatus":null,"severity":"error","filePath":"src/textual/worker.py","lineNumber":322,"sourceCode":"            return run_awaitable(work())\n\n        def run_callable(work: Callable[[], ResultType]) -> ResultType:\n            \"\"\"Set the active worker, and call the callable.\"\"\"\n            active_worker.set(self)\n            return work()\n\n        if (\n            inspect.iscoroutinefunction(self._work)\n            or hasattr(self._work, \"func\")\n            and inspect.iscoroutinefunction(self._work.func)\n        ):\n            runner = run_coroutine\n        elif inspect.isawaitable(self._work):\n            runner = run_awaitable\n        elif callable(self._work):\n            runner = run_callable\n        else:\n            raise WorkerError(\"Unsupported attempt to run a thread worker\")\n\n        loop = asyncio.get_running_loop()\n        assert loop is not None\n        return await loop.run_in_executor(None, runner, self._work)\n\n    async def _run_async(self) -> ResultType:\n        \"\"\"Run an async worker.\n\n        Returns:\n            Return value of the work.\n        \"\"\"\n        if (\n            inspect.iscoroutinefunction(self._work)\n            or hasattr(self._work, \"func\")\n            and inspect.iscoroutinefunction(self._work.func)\n        ):\n            return await self._work()\n        elif inspect.isawaitable(self._work):","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/worker.py#L304-L340","documentation":"WorkerError raised in Worker._run_threaded: the work object is neither a coroutine, an awaitable, nor callable, so the thread-pool runner cannot execute it. This indicates a misconfigured Worker rather than a runtime failure.","triggerScenarios":"Constructing Worker (or calling run_worker with thread=True) with a non-callable — e.g. an already-consumed coroutine's result, an int/str, or an object whose __call__ was removed. Rare; usually surfaces in tests or dynamic dispatch.","commonSituations":"Passing a variable that was accidentally awaited/consumed earlier; passing a class instead of an instance with __call__.","solutions":["Pass a plain function to thread workers: `run_worker(my_function, thread=True)`.","Ensure the object is callable (`callable(obj)`) before scheduling.","Don't pass coroutines to thread workers — those take the async path."],"exampleFix":"# before\nself.run_worker(result, thread=True)\n# after\nself.run_worker(load_data, thread=True)","handlingStrategy":"validation","validationCode":"import inspect\nif not (inspect.isawaitable(work) or callable(work)):\n    raise ValueError('work must be callable or awaitable')","typeGuard":"def is_runnable(w: object) -> bool:\n    return callable(w) or inspect.isawaitable(w)","tryCatchPattern":"from textual.worker import WorkerError\ntry:\n    self.run_worker(work, thread=True)\nexcept WorkerError as e:\n    log(e)","preventionTips":["Always pass a function object to thread workers","Validate dynamic work items before scheduling"],"tags":["worker","thread","type-error","textual"],"backgroundTag":"worker-misconfiguration","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}