RustPython/RustPython · error · TypeError
An asyncio.Future, a coroutine or an awaitable is required
Error message
An asyncio.Future, a coroutine or an awaitable is required
What it means
Runner.run() accepts a coroutine, or any awaitable (futures, objects with __await__) which it wraps transparently via _wrap_awaitable. Passing anything else — an int, str, list, an already-computed result, or a coroutine function that was never called — raises TypeError('An asyncio.Future, a coroutine or an awaitable is required'). This mirrors asyncio.run()'s contract for its main argument.
Source
Thrown at Lib/asyncio/runners.py:104
return self._loop
def run(self, coro, *, context=None):
"""Run code in the embedded event loop."""
if events._get_running_loop() is not None:
# fail fast with short traceback
raise RuntimeError(
"Runner.run() cannot be called from a running event loop")
self._lazy_init()
if not coroutines.iscoroutine(coro):
if inspect.isawaitable(coro):
async def _wrap_awaitable(awaitable):
return await awaitable
coro = _wrap_awaitable(coro)
else:
raise TypeError('An asyncio.Future, a coroutine or an '
'awaitable is required')
if context is None:
context = self._context
task = self._loop.create_task(coro, context=context)
if (threading.current_thread() is threading.main_thread()
and signal.getsignal(signal.SIGINT) is signal.default_int_handler
):
sigint_handler = functools.partial(self._on_sigint, main_task=task)
try:
signal.signal(signal.SIGINT, sigint_handler)
except ValueError:
# `signal.signal` may throw if `threading.main_thread` does
# not support signals (e.g. embedded interpreter with signals
# not registered - see gh-91880)
sigint_handler = NoneView on GitHub (pinned to aaeab4f754)
Solutions
- Pass the coroutine object: runner.run(main(args)) — note the parentheses
- Pre-check arbitrary work with inspect.iscoroutine(work) or inspect.isawaitable(work) before calling run()
- Wrap plain values in an async function: runner.run(process(value))
Example fix
# before runner.run(main) # function object, not a coroutine -> TypeError # after runner.run(main()) # coroutine object
Defensive patterns
Strategy: type-guard
Validate before calling
import inspect
def as_awaitable(work):
if inspect.iscoroutine(work) or inspect.isawaitable(work):
return work
raise TypeError(
f"Runner.run needs a coroutine or awaitable, got {type(work).__name__}")
runner.run(as_awaitable(work)) Type guard
import inspect
def is_awaitable(obj) -> bool:
return inspect.iscoroutine(obj) or inspect.isawaitable(obj) Prevention
- Always call the coroutine function: run(main()), not run(main)
- Type-annotate the parameter as Coroutine and enforce with mypy
- Use inspect.isawaitable() as the general pre-check before passing arbitrary 'work' objects
When it happens
Trigger: runner.run(42) or runner.run('text'); runner.run(main) (function object instead of main()); passing the return value of a synchronous client call; generic driver code receiving 'work' of unknown type.
Common situations: Forgetting the call parentheses on the coroutine function; passing results of sync libraries (requests, database drivers) into the Runner; wrappers that accept either a value or a coroutine without distinguishing them.
Related errors
- data argument must be a bytes-like object, not {type(data)._
- data argument must be bytes-like object (%r)
- Runner.run() cannot be called from a running event loop
- Runner is closed
- Invalid file object: {fd!r}
AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17).
Data as JSON: /api/errors/858799eda55be050.
Report an issue: GitHub.