encode/httpx · error · RuntimeError

Attempted to send a sync request with an AsyncClient instanc

Error message

Attempted to send a sync request with an AsyncClient instance.

What it means

Raised as RuntimeError by AsyncClient._send_single_request when request.stream is not an AsyncByteStream. The body was built from a sync iterable/generator, which the async client cannot await.

Source

Thrown at httpx/_client.py:1725

                if follow_redirects:
                    await response.aread()
                else:
                    response.next_request = request
                    return response

            except BaseException as exc:
                await response.aclose()
                raise exc

    async def _send_single_request(self, request: Request) -> Response:
        """
        Sends a single request, without handling any redirections.
        """
        transport = self._transport_for_url(request.url)
        start = time.perf_counter()

        if not isinstance(request.stream, AsyncByteStream):
            raise RuntimeError(
                "Attempted to send a sync request with an AsyncClient instance."
            )

        with request_context(request=request):
            response = await transport.handle_async_request(request)

        assert isinstance(response.stream, AsyncByteStream)
        response.request = request
        response.stream = BoundAsyncStream(
            response.stream, response=response, start=start
        )
        self.cookies.extract_cookies(response)
        response.default_encoding = self._default_encoding

        logger.info(
            'HTTP Request: %s %s "%s %d %s"',
            request.method,
            request.url,

View on GitHub (pinned to b5addb64f0)

Solutions

  1. Provide an async iterable (async generator yielding bytes) as content for AsyncClient.
  2. Or use the sync httpx.Client for sync content sources.

Example fix

// before
def gen(): yield b"data"
await client.send(httpx.Request("POST", url, content=gen()))  # RuntimeError
// after
async def gen(): yield b"data"
await client.post(url, content=gen())
Defensive patterns

Strategy: type-guard

Validate before calling

import collections.abc as abc

def is_async_content(content) -> bool:
    return isinstance(content, abc.AsyncIterable)

# for AsyncClient, ensure content is an async iterable (or bytes/str)
assert is_async_content(content) or isinstance(content, (bytes, str)), \
    "sync-only content cannot be used with AsyncClient"

Type guard

import collections.abc as abc

def is_async_content(content) -> bool:
    return isinstance(content, abc.AsyncIterable)

Try / catch

try:
    await client.send(req)
except RuntimeError as exc:
    if "sync request with an AsyncClient" in str(exc):
        raise RuntimeError("Use sync httpx.Client for sync-iterable content") from exc
    raise

Prevention

When it happens

Trigger: Building an httpx.Request with a sync generator/iterable as content and sending it through AsyncClient.send()/request().

Common situations: Passing a sync bytes-iterator (e.g. a plain generator yielding bytes) into an async client; reusing a request constructed for the sync client in async code.

Related errors


AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04). Data as JSON: /data/errors/fc42cfa728a81acb.json. Report an issue: GitHub.