python/cpython · error · TypeError

expect a list of futures, not {type(fs).__name__}

Error message

expect a list of futures, not {type(fs).__name__}

What it means

TypeError raised by asyncio.wait() when its first argument is a single Future or coroutine object rather than an iterable of them. wait() operates on collections; a bare awaitable is almost certainly a mistake (usually a forgotten wrapper), and passing a single coroutine would also be silently mis-iterated, so it is rejected with the offending type name.

Source

Thrown at Lib/asyncio/tasks.py:420

ALL_COMPLETED = concurrent.futures.ALL_COMPLETED


async def wait(fs, *, timeout=None, return_when=ALL_COMPLETED):
    """Wait for the Futures or Tasks given by fs to complete.

    The fs iterable must not be empty.

    Returns two sets of Future: (done, pending).

    Usage:

        done, pending = await asyncio.wait(fs)

    Note: This does not raise TimeoutError! Futures that aren't done
    when the timeout occurs are returned in the second set.
    """
    if futures.isfuture(fs) or coroutines.iscoroutine(fs):
        raise TypeError(f"expect a list of futures, not {type(fs).__name__}")
    if not fs:
        raise ValueError('Set of Tasks/Futures is empty.')
    if return_when not in (FIRST_COMPLETED, FIRST_EXCEPTION, ALL_COMPLETED):
        raise ValueError(f'Invalid return_when value: {return_when}')

    fs = set(fs)

    if any(coroutines.iscoroutine(f) for f in fs):
        raise TypeError("Passing coroutines is forbidden, use tasks explicitly.")

    loop = events.get_running_loop()
    return await _wait(fs, timeout, return_when, loop)


def _release_waiter(waiter, *args):
    if not waiter.done():
        waiter.set_result(None)

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Wrap single awaitables in a list: await asyncio.wait([task])
  2. Prefer asyncio.gather for 'await all of these' semantics and asyncio.wait for set-based done/pending control — often the call should not be wait() at all
  3. Normalize inputs upstream: always build a list of tasks before calling wait

Example fix

// before
done, pending = await asyncio.wait(slow_op())

// after
done, pending = await asyncio.wait([asyncio.ensure_future(slow_op())])
Defensive patterns

Strategy: type-guard

Validate before calling

null

Type guard

import asyncio, collections.abc

def is_awaitable_collection(fs) -> bool:
    return isinstance(fs, collections.abc.Iterable) and not isinstance(fs, (asyncio.Future, asyncio.Task))

def to_task_set(fs):
    items = [fs] if not isinstance(fs, collections.abc.Iterable) or isinstance(fs, (asyncio.Future,)) else list(fs)
    return [asyncio.ensure_future(i) for i in items]

Try / catch

null

Prevention

When it happens

Trigger: asyncio.wait(task) instead of asyncio.wait([task]); asyncio.wait(coro) with a coroutine object; passing a single future returned by a helper when only one item is pending.

Common situations: Dynamic gather sites where the list sometimes has one element and a fast path passes it unwrapped; refactors from asyncio.wait_for or await that left the single awaitable bare; copy-paste between wait() and gather() signatures.

Related errors


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