psf/requests · error · RuntimeError
The content for this response was already consumed
Error message
The content for this response was already consumed
What it means
A `RuntimeError` raised by the `Response.content` property when the response body was already consumed from the underlying stream (`_content_consumed` is True) but never cached into `_content` (still False). This happens only for streamed responses: once you iterate the raw stream, the bytes are gone from the socket, so a later `.content`/`.text`/`.json()` access cannot recover them.
Source
Thrown at src/requests/models.py:1041
if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]:
pending = lines.pop()
else:
pending = None
yield from lines
if pending is not None:
yield pending
@property
def content(self) -> bytes:
"""Content of the response, in bytes."""
if self._content is False:
# Read the contents.
if self._content_consumed:
raise RuntimeError("The content for this response was already consumed")
if self.status_code == 0 or self.raw is None:
self._content = None
else:
self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""
self._content_consumed = True
# don't need to release the connection; that's been handled by urllib3
# since we exhausted the data.
return self._content # type: ignore[return-value]
@property
def text(self) -> str:
"""Content of the response, in unicode.
If Response.encoding is None, encoding will be guessed using
``charset_normalizer`` or ``chardet``.
View on GitHub ↗ (pinned to 414f0513c3)
Solutions
- Access `resp.content` (or `.text`/`.json()`) FIRST — it caches the whole body, and subsequent `iter_content` calls replay from the cache.
- If you need both streaming and later access, tee the chunks yourself: collect them into a buffer while streaming and reuse that buffer.
- If streaming isn't actually needed, drop `stream=True` so the body is read and cached eagerly.
- Don't reuse a drained streamed Response across consumers — re-request or pass the saved bytes instead.
Example fix
# before
resp = requests.get(url, stream=True)
for chunk in resp.iter_content(8192):
f.write(chunk)
log.debug(resp.text) # RuntimeError
# after
resp = requests.get(url, stream=True)
buf = bytearray()
for chunk in resp.iter_content(8192):
f.write(chunk)
buf.extend(chunk)
log.debug(buf.decode(resp.encoding or 'utf-8')) Defensive patterns
Strategy: try-catch
Validate before calling
# safe to touch .content only if already consumed or stream still open can_read = resp._content is not False or not resp.raw.closed # or simply: access resp.content once and reuse it
Try / catch
try:
body = resp.content
except RuntimeError:
# stream was partially read via iter_content/raw then closed
... # re-issue the request; the body is unrecoverable Prevention
- With stream=True, consume the body exactly once — either iterate iter_content OR read .content/.text, never both
- Access resp.content once and cache it in a variable instead of re-reading the stream
- Don't call resp.close() (or exit a `with` block) before you've read the body
- If mixing is unavoidable, call resp.content first — it caches, and later .text/.json() reuse the cache
When it happens
Trigger: With `requests.get(url, stream=True)`: first drain the body via `iter_content()`/`iter_lines()` (or `raw.read`), then access `resp.content`, `resp.text`, or `resp.json()`. Accessing `.content` first and iterating later does NOT raise — caching only fails in the stream-then-access order.
Common situations: Logging middleware or debugging code that calls `resp.text` after the application already streamed the body to disk; retry/error handlers that try to read `resp.json()` from a response that was partially streamed; sharing a streamed Response object between two consumers.
Related errors
- Streamed bodies and files are mutually exclusive.
- chunk_size must be an int, it is instead a {type(chunk_size)
- An error occurred when rewinding request body for redirect.
- Unable to rewind request body for redirect.
- Files must be provided.
AI-assisted analysis of psf/requests@414f0513c3 (2026-07-31).
Data as JSON: /data/errors/d7997d5baf4be9bb.json.
Report an issue: GitHub ↗.