openai/openai-python · error · RuntimeError

Didn't receive a `response.completed` event.

Error message

Didn't receive a `response.completed` event.

What it means

Raised by get_final_response on a Responses API streaming run: after until_done() drains the stream, no response.completed event was ever captured into _state._completed_response. The Responses protocol always terminates a successful stream with response.completed; its absence means the stream ended abnormally (connection cut, error event, or early break by the caller).

Source

Thrown at src/openai/lib/streaming/responses/_responses.py:85

    ) -> None:
        self.close()

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

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

    def get_final_response(self) -> ParsedResponse[TextFormatT]:
        """Waits until the stream has been read to completion and returns
        the accumulated `ParsedResponse` object.
        """
        self.until_done()
        response = self._state._completed_response
        if not response:
            raise RuntimeError("Didn't receive a `response.completed` event.")

        return response

    def until_done(self) -> Self:
        """Blocks until the stream has been consumed."""
        consume_sync_iterator(self)
        return self


class ResponseStreamManager(Generic[TextFormatT]):
    def __init__(
        self,
        api_request: Callable[[], Stream[RawResponseStreamEvent]],
        *,
        text_format: type[TextFormatT] | Omit,
        input_tools: Iterable[ToolParam] | Omit,
        starting_after: int | None,
    ) -> None:

View on GitHub (pinned to 9917c6e28e)

Solutions

  1. Check for APIError/connection errors raised while iterating; retry the request on abnormal termination
  2. Increase or disable idle/read timeouts (client.with_options(timeout=...)) for long generations
  3. Do not break out of stream iteration before the terminal event if you need the final response
  4. Verify on a current SDK version and stable API version; report persistent premature terminations

Example fix

# before
response = stream.get_final_response()  # raises if stream was cut

# after
try:
    response = stream.get_final_response()
except RuntimeError:
    response = client.responses.create(..., stream=False)  # retry non-streaming
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

try:
    response = stream.get_final_response()
except RuntimeError as e:
    if "response.completed" in str(e):
        response = client.responses.create(model=model, input=input)  # non-streaming retry

Prevention

When it happens

Trigger: Calling get_final_response() after the SSE connection dropped mid-stream, after the server sent an error/failed event instead of response.completed, or after breaking out of the event loop before completion (so until_done cannot see the terminal event).

Common situations: Network interruptions during long Responses streams; proxies/load balancers with idle timeouts killing SSE; using stream=False semantics expectations with stream=True; early client-side cancellation; beta API changes.

Related errors


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