encode/httpx · error · RuntimeError
Attempted to call a sync iterator on an async stream.
Error message
Attempted to call a sync iterator on an async stream.
What it means
Raised as `RuntimeError` by sync `iter_raw()` when `self.stream` is not a `SyncByteStream`. It means the Response is backed by an async stream (produced via `AsyncClient`) but you called a sync iteration method. httpx keeps sync and async transports strictly separate and will not bridge them implicitly.
Source
Thrown at httpx/_models.py:944
def iter_lines(self) -> typing.Iterator[str]:
decoder = LineDecoder()
with request_context(request=self._request):
for text in self.iter_text():
for line in decoder.decode(text):
yield line
for line in decoder.flush():
yield line
def iter_raw(self, chunk_size: int | None = None) -> typing.Iterator[bytes]:
"""
A byte-iterator over the raw response content.
"""
if self.is_stream_consumed:
raise StreamConsumed()
if self.is_closed:
raise StreamClosed()
if not isinstance(self.stream, SyncByteStream):
raise RuntimeError("Attempted to call a sync iterator on an async stream.")
self.is_stream_consumed = True
self._num_bytes_downloaded = 0
chunker = ByteChunker(chunk_size=chunk_size)
with request_context(request=self._request):
for raw_stream_bytes in self.stream:
self._num_bytes_downloaded += len(raw_stream_bytes)
for chunk in chunker.decode(raw_stream_bytes):
yield chunk
for chunk in chunker.flush():
yield chunk
self.close()
def close(self) -> None:
"""View on GitHub (pinned to b5addb64f0)
Solutions
- Use the async equivalents: `await response.aread()`, `async for chunk in response.aiter_bytes():`.
- Keep sync and async response handling in separate, clearly-typed helper functions.
- If you must bridge, run the async client inside `asyncio.run(...)` and consume via async APIs.
- Type your helpers as accepting `httpx.Response` vs `httpx.AsyncClient`-produced responses distinctly.
Example fix
// before
async with httpx.AsyncClient() as c:
r = await c.get(url)
for c in r.iter_bytes(): # RuntimeError: sync iterator on async stream
...
// after
async with httpx.AsyncClient() as c:
r = await c.get(url)
async for c in r.aiter_bytes():
... Defensive patterns
Strategy: type-guard
Validate before calling
from httpx._transports.default import AsyncByteStream, SyncByteStream
def is_async_response(resp: httpx.Response) -> bool:
return isinstance(resp.stream, AsyncByteStream) Type guard
import httpx
from httpx._transports.default import AsyncByteStream
def is_async_stream(resp: httpx.Response) -> bool:
return isinstance(resp.stream, AsyncByteStream) Try / catch
try:
for chunk in response.iter_bytes():
...
except RuntimeError:
# called sync method on async stream - switch to async
async for chunk in response.aiter_bytes():
... Prevention
- Pair every async client with async iteration methods only.
- Keep sync and async response helpers fully separate and type-annotated.
- Let mypy flag mismatches by typing helpers as accepting AsyncClient-only.
When it happens
Trigger: Calling `response.iter_raw()` / `iter_bytes()` / `response.read()` (sync) on a Response obtained from `httpx.AsyncClient`.
Common situations: Mixing `httpx.Client` and `httpx.AsyncClient` in the same code path; converting sync code to async and forgetting to switch `.read()` to `.aread()` and `iter_bytes()` to `aiter_bytes()`; helper functions shared across sync/async callers.
Related errors
- Attempted to call a sync close on an async stream.
- Attempted to call an async iterator on a sync stream.
- Attempted to call an async close on a sync stream.
- Attempted to send an async request with a sync Client instan
- Attempted to send a sync request with an AsyncClient instanc
AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04).
Data as JSON: /data/errors/3f893682a3e30d3e.json.
Report an issue: GitHub.