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
- Check for APIError/connection errors raised while iterating; retry the request on abnormal termination
- Increase or disable idle/read timeouts (client.with_options(timeout=...)) for long generations
- Do not break out of stream iteration before the terminal event if you need the final response
- 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
- Set generous read/idle timeouts for long streams (with_options(timeout=...))
- Do not break out of stream iteration before the terminal event
- Catch and log transport errors during iteration; retry on abnormal termination
- Verify stable API/SDK version pairing for the Responses API
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
- Expected custom parse type to be a subclass of {Stream} or {
- MissingStreamClassError
- WebSocket connection closed with unsent messages
- An error occurred during streaming
- A single event handler cannot be shared between multiple str
AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28).
Data as JSON: /api/errors/6127db38922932c2.
Report an issue: GitHub.