Skip to content

fix(streaming): move error event handling before thread.* check#3452

Open
C1-BA-B1-F3 wants to merge 5 commits into
openai:mainfrom
C1-BA-B1-F3:fix/unreachable-error-check-streaming
Open

fix(streaming): move error event handling before thread.* check#3452
C1-BA-B1-F3 wants to merge 5 commits into
openai:mainfrom
C1-BA-B1-F3:fix/unreachable-error-check-streaming

Conversation

@C1-BA-B1-F3

Copy link
Copy Markdown

Problem

The error event check inside the block in is unreachable because never starts with . This means error events from the SSE stream are silently ignored in the thread event path, instead of raising an .

This is a regression from commit ("fix(streaming): correct indentation").

Fix

Move error event handling to the top of the event loop, before the check, so error events are always handled regardless of context.

Before (unreachable code):

if sse.event and sse.event.startswith("thread."):
    data = sse.json()
    
    if sse.event == "error" and is_mapping(data) and data.get("error"):  # NEVER TRUE!
        raise APIError(...)
    
    yield process_data(...)

After (error events handled first):

if sse.event == "error":  # Handle error events first
    data = sse.json()
    if is_mapping(data) and data.get("error"):
        raise APIError(...)
    raise APIError(...)  # Always raise on error events

if sse.event and sse.event.startswith("thread."):
    data = sse.json()
    yield process_data(...)

Changes

  • : Move error event handling before check in both and
  • : Add tests for error event handling

Fixes #2796

Guard against empty type args when using bare dict or list annotations
(no type parameters, e.g.  instead of ).

Previously:
- construct_type() raised ValueError on bare dict
- construct_type() raised IndexError on bare list
- _transform_recursive() raised IndexError on bare dict

Now these cases gracefully return the data as-is, matching the behavior
of parameterized types when the data already matches.

Fixes openai#3338, openai#3341
…I responses

Fixes openai#3179

The API can return null for the action field in web search calls (e.g.,
when the search is still in progress or the action hasn't been
determined yet). This change makes the action field Optional[Action]
with a default of None, matching the actual API behavior.

This allows users to safely check action.type without getting an
AttributeError when action is None.
When NO_PROXY or other proxy environment variables contain newline
characters (common in Docker, .env files, or shell scripts), httpx's
get_environment_proxies() only splits by comma and fails with InvalidURL.

This fix adds sanitize_proxy_env_vars() that removes newlines from proxy
environment variables before httpx reads them.

Fixes openai#3303
The ActionSearchSource type only supported type='url' with a required url
field, but the API returns specialized data sources (weather, sports,
finance) with type='api', a name field, and url=None.

Changes:
- Add 'api' to the type Literal in both response and param types
- Make url optional (absent when type='api')
- Add optional name field for the data source identifier

Fixes openai#2736
The error event check inside the `if sse.event.startswith("thread.")` block
was unreachable because "error" never starts with "thread.". This meant
error events from the SSE stream were silently ignored in the thread event
path, instead of raising an APIError.

Fix: Move error event handling to the top of the event loop, before the
thread.* check, so error events are always handled regardless of context.

Fixes openai#2796
@C1-BA-B1-F3 C1-BA-B1-F3 requested a review from a team as a code owner June 26, 2026 01:50

@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: b6554a06b8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/openai/_streaming.py
Comment on lines +83 to +87
raise APIError(
message="An error occurred during streaming",
request=self.response.request,
body=data,
)

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 assistant error events

When Assistants streams emit event: error, the payload is the top-level ErrorObject used by AssistantStreamEvent.ErrorEvent, and the assistant stream handlers still have an event.event == "error" branch. This unconditional fallback now raises APIError for that valid event shape because it lacks a nested error key, so consumers of Stream[AssistantStreamEvent]/the assistant helpers can no longer receive the typed error event; the async block has the same behavior.

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