Skip to content

fix(streaming): move unreachable error event check out of thread. branch#2941

Open
MaxwellCalkin wants to merge 1 commit intoopenai:mainfrom
MaxwellCalkin:fix/unreachable-error-event-check
Open

fix(streaming): move unreachable error event check out of thread. branch#2941
MaxwellCalkin wants to merge 1 commit intoopenai:mainfrom
MaxwellCalkin:fix/unreachable-error-event-check

Conversation

@MaxwellCalkin
Copy link

Summary

Fixes #2796.

The sse.event == "error" check in both Stream.__stream__ and AsyncStream.__stream__ is dead code — it's nested inside if sse.event.startswith("thread."), but "error" never starts with "thread.".

Root cause

This was introduced in commit 48188cc when the branch logic was refactored from checking for response.*/transcript.* events first to checking for thread.* events first. The sse.event == "error" check was in the else branch (non-response.* events) before the refactor, but was accidentally placed in the thread.* branch after it. The subsequent indentation fix in abc2596 preserved the mistake.

Before 48188cc (correct):

if sse.event is None or (sse.event.startswith("response.") or ...):
    # generic error check
    if is_mapping(data) and data.get("error"): ...
else:
    # event-specific error check — reachable for event="error"
    if sse.event == "error" and ...: ...

After 48188cc (broken):

if sse.event and sse.event.startswith("thread."):
    # error check is now unreachable — "error" != "thread.*"
    if sse.event == "error" and ...: ...
else:
    if is_mapping(data) and data.get("error"): ...

Fix

Move the error event handling into its own elif sse.event == "error": branch between the thread.* check and the else fallback, so it can actually be reached when the server sends an SSE with event: error.

if sse.event and sse.event.startswith("thread."):
    ...
elif sse.event == "error":
    # now reachable
    ...
else:
    ...

Applied to both Stream.__stream__ (sync) and AsyncStream.__stream__ (async).

Test plan

  • Verify the elif branch is reached for event: error SSEs
  • Verify thread.* events still handled correctly (no behavior change)
  • Verify other events still fall through to else branch

🤖 Generated with Claude Code

The `sse.event == "error"` check in both `Stream.__stream__` and
`AsyncStream.__stream__` was nested inside the
`if sse.event.startswith("thread.")` branch, making it dead code
since "error" never starts with "thread.".

This was introduced in commit 48188cc when the branch logic was
refactored to check for `thread.` events first instead of
`response.*`/`transcript.*` events. The error check was left in the
wrong branch, and the subsequent indentation fix in abc2596
preserved the mistake.

The fix moves the error event handling into its own `elif` branch
so it can actually be reached when the server sends an SSE with
`event: error`.
@MaxwellCalkin MaxwellCalkin requested a review from a team as a code owner March 8, 2026 07:25
Copy link

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

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: e05a9aca74

ℹ️ 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 +71 to +73
elif sse.event == "error":
data = sse.json()
if is_mapping(data) and data.get("error"):

Choose a reason for hiding this comment

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

P1 Badge Preserve event:error items when payload lacks error key

This new elif sse.event == "error" branch no longer yields anything when the payload does not contain a top-level error field, so event:error SSEs can be silently dropped. In Assistants streaming, ErrorEvent is modeled as { "event": "error", "data": ErrorObject } (not {"error": ...}), so this path will skip the APIError raise and also skip process_data, meaning consumers never receive the event; the same regression is duplicated in AsyncStream.__stream__.

Useful? React with 👍 / 👎.

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.

Bug: Dead code - sse.event == "error" check is unreachable in _streaming.py

1 participant