openai/openai-python · critical · WebSocketConnectionClosedError
WebSocket connection closed with unsent messages
Error message
WebSocket connection closed with unsent messages
What it means
Raised by the async WebSocket event iterator (__aiter__) when the connection closes with an error, reconnection fails, and there are still unsent messages queued for transmission. The error preserves the unsent messages so callers can recover or re-send them rather than silently dropping output.
Source
Thrown at src/openai/resources/responses/responses.py:4050
self.response = AsyncResponsesResponseResource(self)
async def __aiter__(self) -> AsyncIterator[ResponsesServerEvent]:
"""
An infinite-iterator that will continue to yield events until
the connection is closed.
"""
from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError
while True:
try:
yield await self.recv()
except ConnectionClosedOK:
return
except ConnectionClosedError as exc:
if not await self._reconnect(exc):
unsent = self._send_queue.drain()
if unsent:
raise WebSocketConnectionClosedError(
"WebSocket connection closed with unsent messages",
unsent_messages=unsent,
) from exc
raise
async def recv(self) -> ResponsesServerEvent:
"""
Receive the next message from the connection and parses it into a `ResponsesServerEvent` object.
Canceling this method is safe. There's no risk of losing data.
"""
return self.parse_event(await self.recv_bytes())
async def recv_bytes(self) -> bytes:
"""Receive the next message from the connection as raw bytes.
Canceling this method is safe. There's no risk of losing data.
View on GitHub (pinned to 9917c6e28e)
Solutions
- Catch WebSocketConnectionClosedError and re-send the unsent_messages on a fresh connection
- Add keep-alive/ping handling or reduce idle time to avoid mid-stream closes
- Implement a reconnect wrapper that re-establishes the session and replays queued output
Example fix
// before
async for event in ws:
handle(event)
// after
try:
async for event in ws:
handle(event)
except WebSocketConnectionClosedError as exc:
for msg in exc.unsent_messages:
await outbox.put(msg) # replay after reconnect Defensive patterns
Strategy: try-catch
Try / catch
from openai._websocket import WebSocketConnectionClosedError
try:
async for event in ws:
await handle(event)
except WebSocketConnectionClosedError as exc:
unsent = exc.unsent_messages
ws = await reconnect()
for msg in unsent:
await ws.send(msg) Prevention
- Drain or flush send queues during idle periods
- Implement reconnect-with-replay around WebSocket sessions
- Monitor connection health and re-send unsent_messages from the exception
- Avoid large bursts of sends right before expected disconnects
When it happens
Trigger: Streaming a Responses WebSocket session, sending events while the network drops; ConnectionClosedError occurs, reconnect logic fails, and self._send_queue.drain() returns pending messages, raising WebSocketConnectionClosedError with unsent_messages attached.
Common situations: Long-running realtime/streaming sessions over unstable networks (WiFi, mobile, proxies with idle timeouts); sending bursts of input events right as the server or intermediary closes the socket.
Understand the failure class
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
Related errors
- Didn't receive a `response.completed` event.
- WebSocket connection closed with unsent messages
- WebSocket connection closed with unsent messages
- WebSocket error: {event}
- Expected custom parse type to be a subclass of {Stream} or {
AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28).
Data as JSON: /api/errors/29faf78fd9181cf0.
Report an issue: GitHub.