Skip to content

fix(realtime): add reconnection resilience to send_raw()#3363

Open
yen0304 wants to merge 3 commits into
openai:mainfrom
yen0304:fix-send-raw-reconnection
Open

fix(realtime): add reconnection resilience to send_raw()#3363
yen0304 wants to merge 3 commits into
openai:mainfrom
yen0304:fix-send-raw-reconnection

Conversation

@yen0304

@yen0304 yen0304 commented Jun 4, 2026

Copy link
Copy Markdown

Summary

  • send_raw() was missing the try/except that send() has for reconnection resilience
  • If the WebSocket disconnects mid-send, the data is silently lost instead of being enqueued for retry after reconnection
  • Fixed in all 4 locations: async/sync variants in both realtime.py and responses.py

send_raw() was missing the try/except that send() has — if the
WebSocket disconnects mid-send, the data is silently lost instead of
being enqueued for retry after reconnection.
@yen0304 yen0304 requested a review from a team as a code owner June 4, 2026 17:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ad91393087

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +368 to +369
raw = data if isinstance(data, str) else data.decode("utf-8")
self._send_queue.enqueue(raw)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve byte payloads when queueing failed raw sends

When send_raw() is called with bytes and the socket drops during send, this decodes the payload and stores it in SendQueue, whose flush path later calls send(str). That changes a binary WebSocket frame into a text frame for UTF-8 bytes, and for arbitrary binary bytes (for example audio chunks containing 0xff) raises UnicodeDecodeError before the original connection failure can be re-raised or the message queued. Since send_raw explicitly accepts bytes, the retry path should retain the original frame type instead of forcing UTF-8 text; the same new exception-path conversion appears in the sync and Responses variants as well.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point — you are right that the .decode("utf-8") I introduced was incorrect, not just an inherited limitation. Fixed properly:

  • SendQueue now stores bytes | str natively. Byte length is computed as len(data) for bytes and len(data.encode("utf-8")) for str.
  • All four send_raw paths (sync + async × realtime + responses) enqueue data directly without any decode, preserving the original frame type.
  • Added an end-to-end test that drives the real _reconnect() + flush path with a non-UTF-8 binary payload (b"\xff\xfe\x00audio"), confirms it is replayed byte-for-byte after reconnect, and verified the test fails (raising UnicodeDecodeError) against the prior decode-to-UTF-8 implementation.

yen0304 added 2 commits June 9, 2026 23:11
send_raw() accepts bytes | str, but the reconnect/retry path decoded
bytes to UTF-8 before enqueueing. That turned binary WebSocket frames
into text frames and raised UnicodeDecodeError for arbitrary binary
payloads (e.g. audio chunks containing 0xff) before the original
connection failure could surface.

SendQueue now stores bytes | str natively and counts byte length per
type, so send_raw() can enqueue the original payload unchanged on both
the reconnecting and send-failure paths (sync + async, realtime +
responses). Addresses Codex review feedback on openai#3363.
Add an end-to-end test that drives the real _reconnect() + flush path:
a send_raw() with non-UTF-8 bytes fails on a dropped socket, gets
queued, and is replayed byte-for-byte to the new connection after
reconnect. Verified this fails (UnicodeDecodeError) against the prior
decode-to-UTF-8 implementation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant