python/cpython · error · RuntimeError

await wasn't used with future

Error message

await wasn't used with future

What it means

Future.__await__ yields the future once so the event loop can resume the waiter when it completes; after resuming, done() must be True. If the coro was driven by something that did not actually await (bare next() on __iter__, custom drivers that ignore the yielded future), the future is still pending and this RuntimeError fires. It means 'you iterated a future without a real awaiter'.

Source

Thrown at Lib/asyncio/futures.py:301

        if isinstance(exception, StopIteration):
            new_exc = RuntimeError("StopIteration interacts badly with "
                                   "generators and cannot be raised into a "
                                   "Future")
            new_exc.__cause__ = exception
            new_exc.__context__ = exception
            exception = new_exc
        self._exception = exception
        self._exception_tb = exception.__traceback__
        self._state = _FINISHED
        self.__schedule_callbacks()
        self.__log_traceback = True

    def __await__(self):
        if not self.done():
            self._asyncio_future_blocking = True
            yield self  # This tells Task to wait for completion.
        if not self.done():
            raise RuntimeError("await wasn't used with future")
        return self.result()  # May raise too.

    __iter__ = __await__  # make compatible with 'yield from'.


# Needed for testing purposes.
_PyFuture = Future


def _get_loop(fut):
    # Tries to call Future.get_loop() if it's available.
    # Otherwise fallbacks to using the old '_loop' property.
    try:
        get_loop = fut.get_loop
    except AttributeError:
        pass
    else:
        return get_loop()

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Always consume futures with await inside a real asyncio Task (asyncio.run, loop.create_task)
  2. In custom drivers, after the future completes, resume the coroutine with send/close properly
  3. Replace manual iteration with await asyncio.wait([fut])

Example fix

# before
coro = future.__await__()
next(coro)  # manual drive -> RuntimeError on next iteration

# after
result = await future  # inside a coroutine run by asyncio
Defensive patterns

Strategy: validation

Validate before calling

# ensure the awaiter runs inside a real task
assert asyncio.current_task() is not None

Prevention

When it happens

Trigger: Manually driving a coroutine that awaits a future with next(coro.__await__()) outside a loop; using 'yield from future' inside a generator consumed by non-asyncio machinery; a Task implementation that resumes the coroutine without completing the future.

Common situations: Custom task/trampoline implementations; calling coro.send(None) once in tests; mixing curio/trio-style drivers with asyncio futures; debugging tools stepping through coroutines manually.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/6bfe916326503203. Report an issue: GitHub.