{"id":"3f893682a3e30d3e","repo":"encode/httpx","slug":"attempted-to-call-a-sync-iterator-on-an-async-stre","errorCode":null,"errorMessage":"Attempted to call a sync iterator on an async stream.","messagePattern":"Attempted to call a sync iterator on an async stream\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"httpx/_models.py","lineNumber":944,"sourceCode":"    def iter_lines(self) -> typing.Iterator[str]:\n        decoder = LineDecoder()\n        with request_context(request=self._request):\n            for text in self.iter_text():\n                for line in decoder.decode(text):\n                    yield line\n            for line in decoder.flush():\n                yield line\n\n    def iter_raw(self, chunk_size: int | None = None) -> typing.Iterator[bytes]:\n        \"\"\"\n        A byte-iterator over the raw response content.\n        \"\"\"\n        if self.is_stream_consumed:\n            raise StreamConsumed()\n        if self.is_closed:\n            raise StreamClosed()\n        if not isinstance(self.stream, SyncByteStream):\n            raise RuntimeError(\"Attempted to call a sync iterator on an async stream.\")\n\n        self.is_stream_consumed = True\n        self._num_bytes_downloaded = 0\n        chunker = ByteChunker(chunk_size=chunk_size)\n\n        with request_context(request=self._request):\n            for raw_stream_bytes in self.stream:\n                self._num_bytes_downloaded += len(raw_stream_bytes)\n                for chunk in chunker.decode(raw_stream_bytes):\n                    yield chunk\n\n        for chunk in chunker.flush():\n            yield chunk\n\n        self.close()\n\n    def close(self) -> None:\n        \"\"\"","sourceCodeStart":926,"sourceCodeEnd":962,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_models.py#L926-L962","documentation":"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.","triggerScenarios":"Calling `response.iter_raw()` / `iter_bytes()` / `response.read()` (sync) on a Response obtained from `httpx.AsyncClient`.","commonSituations":"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.","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."],"exampleFix":"// before\nasync with httpx.AsyncClient() as c:\n    r = await c.get(url)\nfor c in r.iter_bytes():  # RuntimeError: sync iterator on async stream\n    ...\n\n// after\nasync with httpx.AsyncClient() as c:\n    r = await c.get(url)\n    async for c in r.aiter_bytes():\n        ...","handlingStrategy":"type-guard","validationCode":"from httpx._transports.default import AsyncByteStream, SyncByteStream\n\ndef is_async_response(resp: httpx.Response) -> bool:\n    return isinstance(resp.stream, AsyncByteStream)","typeGuard":"import httpx\nfrom httpx._transports.default import AsyncByteStream\n\ndef is_async_stream(resp: httpx.Response) -> bool:\n    return isinstance(resp.stream, AsyncByteStream)","tryCatchPattern":"try:\n    for chunk in response.iter_bytes():\n        ...\nexcept RuntimeError:\n    # called sync method on async stream - switch to async\n    async for chunk in response.aiter_bytes():\n        ...","preventionTips":["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."],"tags":["sync-async","streaming","asyncio","runtime-error"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}