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

Raised by the Response.content property when the underlying stream has already been consumed (e.g. via iter_content with stream=True) but _content was never populated. This is a RuntimeError, not the more specific StreamConsumedError (which is raised from iter_content itself). It signals an irreversible state: the socket data was read and discarded, so .content cannot materialize the bytes retroactively.

Solutions

  1. Decide on ONE access pattern: either use stream=False and read .content, or use stream=True and fully consume iter_content() — never both.
  2. If you already streamed and need the bytes, collect them during iteration: data = b''.join(resp.iter_content(8192)).
  3. Buffer the stream into a variable early if you need to re-read: raw = resp.content before any streaming call.

Example fix

# before (stream=True)
for chunk in resp.iter_content(8192):
    process(chunk)
body = resp.content  # RuntimeError

# after — collect during iteration
body = b''.join(resp.iter_content(8192))
Defensive patterns

Strategy: validation

Validate before calling

if resp._content_consumed and isinstance(resp._content, bool):
    raise RuntimeError('Content already consumed via streaming')
body = resp.content

Try / catch

try:
    body = resp.content
except RuntimeError:
    # Stream was consumed; re-fetch or use buffered data
    body = cached_stream_data

Prevention

When it happens

Trigger: Calling resp.iter_content() on a streaming response (stream=True) and then accessing resp.content afterwards; iterating over resp.iter_lines() and then calling resp.content; calling resp.content after resp.content on a streaming response whose _content is still False but _content_consumed was set True by a prior generator iteration.

Common situations: Mixing streaming and non-streaming access patterns on the same Response object; a helper function that calls iter_content() internally followed by code that reads .content; refactoring from stream=False to stream=True without updating downstream .content access.

Related errors


AI-assisted analysis of psf/requests@8068356288 (2026-08-11). Data as JSON: /api/errors/d7997d5baf4be9bb. Report an issue: GitHub.

Appendix: 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 8068356288)