python/cpython · error · TypeError
expects an iterable of awaitables, not {type(fs).__name__}
Error message
expects an iterable of awaitables, not {type(fs).__name__} What it means
Raised by asyncio.as_completed() when its first argument is a single awaitable instead of an iterable of awaitables. The guard `inspect.isawaitable(fs)` exists to catch the common mistake of passing one coroutine where a list is expected, which would otherwise iterate the object in confusing ways or silently do nothing.
Source
Thrown at Lib/asyncio/tasks.py:671
awaitable. This pattern is compatible with Python versions older than
3.13:
ipv4_connect = create_task(open_connection("127.0.0.1", 80))
ipv6_connect = create_task(open_connection("::1", 80))
tasks = [ipv4_connect, ipv6_connect]
for next_connect in as_completed(tasks):
# next_connect is not one of the original task objects. It must
# be awaited to obtain the result value or raise the exception
# of the awaitable that finishes next.
reader, writer = await next_connect
A TimeoutError is raised if the timeout occurs before all awaitables
are done. This is raised by the async for loop during asynchronous
iteration or by the coroutines yielded during plain iteration.
"""
if inspect.isawaitable(fs):
raise TypeError(
f"expects an iterable of awaitables, not {type(fs).__name__}"
)
return _AsCompletedIterator(fs, timeout)
@types.coroutine
def __sleep0():
"""Skip one event loop run cycle.
This is a private helper for 'asyncio.sleep()', used
when the 'delay' is set to 0. It uses a bare 'yield'
expression (which Task.__step knows how to handle)
instead of creating a Future object.
"""
yield
View on GitHub (pinned to bc6749cc3b)
Solutions
- Wrap the single awaitable in a list: `for coro in asyncio.as_completed([fetch(url)])`
- If there is only one awaitable, just `await fetch(url)` directly — no iterator needed
- When building from a loop, pass a list comprehension: `asyncio.as_completed([fetch(u) for u in urls])`
Example fix
// before
for nxt in asyncio.as_completed(fetch(url)):
...
// after
for nxt in asyncio.as_completed([fetch(url)]):
result = await nxt Defensive patterns
Strategy: validation
Validate before calling
import inspect, asyncio
arg = fetch(url) # maybe a single awaitable
if inspect.isawaitable(arg) and not hasattr(arg, '__iter__'):
arg = [arg] # normalize single awaitable to a list
for nxt in asyncio.as_completed(arg):
result = await nxt Type guard
import inspect
from typing import Any, Iterable, Awaitable
def is_awaitable_iterable(obj: Any) -> bool:
"""True if obj is safe to pass to asyncio.as_completed."""
return not inspect.isawaitable(obj) and isinstance(obj, Iterable) and all(
inspect.isawaitable(x) for x in obj
) Try / catch
try:
it = asyncio.as_completed(fs)
except TypeError:
it = asyncio.as_completed([fs]) # single awaitable was passed Prevention
- Always pass a list comprehension of awaitables to as_completed
- If handling exactly one awaitable, await it directly instead
- Wrap construction of awaitable collections in one helper so the shape is uniform
When it happens
Trigger: Calling `asyncio.as_completed(fetch(url))` instead of `asyncio.as_completed([fetch(url)])`; also passing a single Task or Future where the API expects a list/iterable of them.
Common situations: Refactoring code that previously awaited a single coroutine into an as_completed loop; copy-pasting a gather() call pattern into as_completed() without wrapping the single item in a list.
Related errors
- Passing coroutines is forbidden, use tasks explicitly.
- Failed to fetch glossary.json
- d3-flame-graph library failed to load
- Not implemented
- Unimplemented ioctl request
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/4210431caa33c439.
Report an issue: GitHub.