Textualize/textual · error · WorkerError
Request to run a non-async function as an async worker
Error message
Request to run a non-async function as an async worker
What it means
WorkerError from Worker._run_async: the worker was started in async mode but the work item is a plain (non-async) callable. Async workers execute coroutines/awaitables only; sync callables must run as thread workers.
Source
Thrown at src/textual/worker.py:343
assert loop is not None
return await loop.run_in_executor(None, runner, self._work)
async def _run_async(self) -> ResultType:
"""Run an async worker.
Returns:
Return value of the work.
"""
if (
inspect.iscoroutinefunction(self._work)
or hasattr(self._work, "func")
and inspect.iscoroutinefunction(self._work.func)
):
return await self._work()
elif inspect.isawaitable(self._work):
return await self._work
elif callable(self._work):
raise WorkerError("Request to run a non-async function as an async worker")
raise WorkerError("Unsupported attempt to run an async worker")
async def run(self) -> ResultType:
"""Run the work.
Implement this method in a subclass, or pass a callable to the constructor.
Returns:
Return value of the work.
"""
return await (
self._run_threaded() if self._thread_worker else self._run_async()
)
async def _run(self, app: App) -> None:
"""Run the worker.
Args:View on GitHub (pinned to 06dbeef4bb)
Solutions
- Add thread=True: `self.run_worker(my_sync_fn, thread=True)` or `@work(thread=True)`.
- Or make the function async (`async def`) so the async runner can await it.
Example fix
# before def load(): ... self.run_worker(load) # after def load(): ... self.run_worker(load, thread=True)
Defensive patterns
Strategy: validation
Validate before calling
import inspect
if callable(fn) and not inspect.iscoroutinefunction(fn):
self.run_worker(fn, thread=True)
else:
self.run_worker(fn) Type guard
import inspect
def is_async_callable(fn) -> bool:
f = getattr(fn, 'func', fn)
return inspect.iscoroutinefunction(f) Try / catch
from textual.worker import WorkerError
try:
await worker.run()
except WorkerError:
worker._run_threaded() Prevention
- Mark @work methods thread=True when they block
- Keep blocking I/O out of async workers
When it happens
Trigger: `run_worker(plain_function)` with default exclusive/thread settings that route to _run_async (i.e. not thread=True), or calling `worker.run()` on a Worker wrapping a normal function in async mode.
Common situations: Forgetting the `thread=True` (or @work(thread=True)) argument when passing a blocking function; refactoring an async worker into a sync function without updating flags.
Related errors
- Can not create a worker from a non-async function unless `th
- Unsupported attempt to run a thread 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/5a4894b3b5453fcc.
Report an issue: GitHub.