openai/openai-python · error · StreamAlreadyConsumed

StreamAlreadyConsumed

Error message

StreamAlreadyConsumed

What it means

The synchronous response's read() re-raises httpx's 'response already read' error as StreamAlreadyConsumed. A streaming response body can only be consumed once; calling read()/text()/json()/parse() again after the body was already read or iterated raises this.

Source

Thrown at src/openai/_response.py:346

        parsed = self._parse(to=to)
        if is_given(self._options.post_parser):
            parsed = self._options.post_parser(parsed)

        if isinstance(parsed, BaseModel):
            add_request_id(parsed, self.request_id)

        self._parsed_by_type[cache_key] = parsed
        return cast(R, parsed)

    def read(self) -> bytes:
        """Read and return the binary response content."""
        try:
            return self.http_response.read()
        except stream_consumed_exceptions() as exc:
            # The default error raised by httpx isn't very
            # helpful in our case so we re-raise it with
            # a different error message.
            raise StreamAlreadyConsumed() from exc

    def text(self) -> str:
        """Read and decode the response content into a string."""
        self.read()
        return self.http_response.text

    def json(self) -> object:
        """Read and decode the JSON response content."""
        self.read()
        return self.http_response.json()

    def close(self) -> None:
        """Close the response and release the connection.

        Automatically called if the response body is read to completion.
        """
        self.http_response.close()

View on GitHub (pinned to 9917c6e28e)

Solutions

  1. Store the read result once and reuse it instead of re-reading
  2. If you need both text and parsed output, call read() once then use .text or .parse on the cached content
  3. Re-issue the API request to get a fresh response stream

Example fix

// before
body = resp.text()
... later ...
again = resp.read()  # StreamAlreadyConsumed

// after
body = resp.text()
data = resp.parse(MyModel)  # uses already-read content, no re-read
Defensive patterns

Strategy: try-catch

Validate before calling

data = resp.read()  # read exactly once, up front
# subsequent parsing uses cached content:
model = resp.parse(MyModel)

Try / catch

from openai import StreamAlreadyConsumed
try:
    body = resp.read()
except StreamAlreadyConsumed:
    body = cached_body  # fall back to previously read content

Prevention

When it happens

Trigger: Calling response.read() (or .text(), .json(), .parse()) twice on the same APIResponse, or calling read() after the stream was already consumed by iteration or by an earlier access.

Common situations: Retrying logic that re-reads a response, logging the body and then parsing it, or caching/inspecting a response object after it was already consumed.

Related errors


AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28). Data as JSON: /api/errors/58515f4c8d9a95d3. Report an issue: GitHub.