encode/httpx · error · RuntimeError
Attempted to call a sync close on an async stream.
Error message
Attempted to call a sync close on an async stream.
What it means
Raised as `RuntimeError` by sync `close()` when `self.stream` is not a `SyncByteStream`. You called the sync close on a Response whose underlying stream is async (came from `AsyncClient`). Closing an async stream synchronously would not release the connection correctly, so it is rejected.
Source
Thrown at httpx/_models.py:967
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:
"""
Close the response and release the connection.
Automatically called if the response body is read to completion.
"""
if not isinstance(self.stream, SyncByteStream):
raise RuntimeError("Attempted to call a sync close on an async stream.")
if not self.is_closed:
self.is_closed = True
with request_context(request=self._request):
self.stream.close()
async def aread(self) -> bytes:
"""
Read and return the response content.
"""
if not hasattr(self, "_content"):
self._content = b"".join([part async for part in self.aiter_bytes()])
return self._content
async def aiter_bytes(
self, chunk_size: int | None = None
) -> typing.AsyncIterator[bytes]:
"""View on GitHub (pinned to b5addb64f0)
Solutions
- Use `await response.aclose()` for async responses.
- Inside an async context manager, prefer `async with client.stream(...)` which acloses automatically.
- Branch on transport type if a shared cleanup helper is unavoidable.
- Keep sync/async response lifecycles fully separated.
Example fix
// before r = await async_client.get(url) r.close() # RuntimeError // after r = await async_client.get(url) await r.aclose()
Defensive patterns
Strategy: type-guard
Validate before calling
from httpx._transports.default import AsyncByteStream
def needs_aclose(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:
response.close()
except RuntimeError:
await response.aclose() Prevention
- Always aclose() async responses; close() sync responses.
- Prefer async with client.stream(...) which manages aclose automatically.
- Never share cleanup helpers across sync/async code paths.
When it happens
Trigger: Calling `response.close()` (sync) on a Response produced by `httpx.AsyncClient`.
Common situations: Same as error 48: mixing sync/async clients, partial async migration, shared helpers, or framework finalizers that call `.close()` regardless of the transport type.
Related errors
- Attempted to call an async close on a sync stream.
- Attempted to call a sync iterator on an async stream.
- Attempted to call an async iterator 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/7154502aebe06f73.json.
Report an issue: GitHub.