aio-libs/aiohttp · error · TypeError

value argument must support collections.abc.AsyncIterable in

Error message

value argument must support collections.abc.AsyncIterable interface, got {type(value)!r}

What it means

Raised by AsyncIterablePayload.__init__ when the supplied value does not implement collections.abc.AsyncIterable. aiohttp uses this payload type to stream request/response bodies from an async producer, so it strictly requires an object with a working __aiter__/__anext__ protocol. Passing a plain list, a synchronous generator, bytes, or any non-async iterable triggers it. The error message reports the actual type via {type(value)!r} for diagnosis.

Source

Thrown at aiohttp/payload.py:985

    ) -> None:
        super().__init__(
            dumps(value),
            content_type=content_type,
            *args,
            **kwargs,
        )


class AsyncIterablePayload(Payload):
    _iter: AsyncIterator[bytes] | None = None
    _value: AsyncIterable[bytes]
    _cached_chunks: list[bytes] | None = None
    # _consumed stays False to allow reuse with cached content
    _autoclose = True  # Iterator doesn't need explicit closing

    def __init__(self, value: AsyncIterable[bytes], *args: Any, **kwargs: Any) -> None:
        if not isinstance(value, AsyncIterable):
            raise TypeError(
                "value argument must support "
                "collections.abc.AsyncIterable interface, "
                f"got {type(value)!r}"
            )

        if "content_type" not in kwargs:
            kwargs["content_type"] = "application/octet-stream"

        super().__init__(value, *args, **kwargs)

        self._iter = value.__aiter__()

    async def write(self, writer: AbstractStreamWriter) -> None:
        """
        Write the entire async iterable payload to the writer stream.

        Args:
            writer: An AbstractStreamWriter instance that handles the actual writing

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Pass an async iterable: an async generator function CALLED (e.g. async_gen()), an object implementing __aiter__, or an aiohttp.StreamReader.
  2. If you only have a sync iterator, wrap it: async def gen(): for chunk in sync_iter: yield chunk, then pass gen().
  3. For bytes/str already fully materialized, use BytesPayload (or just pass data=bytes) instead of AsyncIterablePayload.
  4. Register a custom Payload subclass via PAYLOAD_REGISTRY.register(MyPayload, MyType) if you need first-class support for your type.

Example fix

// before
async def producer():
    for chunk in chunks:  # sync loop, not async
        yield chunk
payload = AsyncIterablePayload(producer())
// after
async def producer():
    for chunk in chunks:
        yield chunk  # still works only if it is `async def`
payload = AsyncIterablePayload(producer())
# Or, for already-materialized bytes:
from aiohttp import payload
p = payload.BytesPayload(b'data')
Defensive patterns

Strategy: type-guard

Validate before calling

from collections.abc import AsyncIterable

def is_async_iterable(obj) -> bool:
    return isinstance(obj, AsyncIterable)

# before constructing:
if not is_async_iterable(value):
    raise TypeError(f'expected async iterable, got {type(value).__name__}')
payload = AsyncIterablePayload(value)

Type guard

from collections.abc import AsyncIterable
from typing import Any, TypeGuard

def is_async_iterable(obj: Any) -> TypeGuard[AsyncIterable[bytes]]:
    return isinstance(obj, AsyncIterable)

Try / catch

from collections.abc import AsyncIterable
try:
    payload = AsyncIterablePayload(value)
except TypeError:
    # fall back to materializing the body
    payload = BytesPayload(bytes(value))

Prevention

When it happens

Trigger: Constructing AsyncIterablePayload(value) directly, or calling aiohttp.payload.get_payload()/payload_type() on an object that is not async iterable (e.g. a sync generator function, list, tuple, bytes, or a custom class lacking __aiter__). Also triggered indirectly by passing such an object as the data= argument to web.Response or client session methods when its class is not registered with PAYLOAD_REGISTRY.

Common situations: Developers migrating from requests/httpx who pass a sync generator to stream a body; passing a list of bytes chunks; using an async generator function object instead of the called coroutine (forgot parentheses); wrapping a sync file object instead of an aiohttp or aiofiles async reader.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/d67425664e5566f3.json. Report an issue: GitHub.