Skip to content

fix(relay): record Responses API stream errors - #6549

Open
seefs001 wants to merge 1 commit into
QuantumNous:mainfrom
seefs001:fix/openai-responses-sse-error
Open

fix(relay): record Responses API stream errors#6549
seefs001 wants to merge 1 commit into
QuantumNous:mainfrom
seefs001:fix/openai-responses-sse-error

Conversation

@seefs001

@seefs001 seefs001 commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

记录 /v1/responses SSE下的error

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling for streaming responses.
    • Clearer error details are now surfaced when a streamed response fails or reports an error.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The OpenAI responses streaming DTO now carries raw error payloads. The stream handler recognizes error and failed response events, resolves nested error data when needed, and reports valid errors through the stream scanner.

Changes

OpenAI response error propagation

Layer / File(s) Summary
Stream error payload propagation
relaykit/dto/openai_response.go, relay/channel/openai/relay_responses.go
ResponsesStreamResponse carries raw error data, while OaiResponsesStreamHandler processes "error", "response.error", and "response.failed" events and forwards valid errors.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: calcium-ion

Poem

I’m a bunny with errors to bear,
Now failed streams are caught with care.
Raw payloads hop through the flow,
Clear messages tell what we know.
No silent thumps in the night—
Every stream error sees the light.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main fix: recording Responses API stream errors in the relay.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@relaykit/dto/openai_response.go`:
- Line 389: The Responses API stream error handling must support top-level error
event fields instead of only nested response.error payloads. In
relaykit/dto/openai_response.go, extend the response DTO around Error with
top-level code, message, and param fields or an equivalent raw fallback; in
relay/channel/openai/relay_responses.go, update the stream response handling to
construct streamError from those top-level values before calling sr.Error(...),
while preserving nested-error handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 25f584cf-ef3e-4a34-808b-e8dbb5b58b63

📥 Commits

Reviewing files that changed from the base of the PR and between 66ee6b8 and 57dbe13.

📒 Files selected for processing (2)
  • relay/channel/openai/relay_responses.go
  • relaykit/dto/openai_response.go

type ResponsesStreamResponse struct {
Type string `json:"type"`
Response *OpenAIResponsesResponse `json:"response,omitempty"`
Error json.RawMessage `json:"error,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)openai_response\.go$|(^|/)relay_responses\.go$|expr\.md$|common/json\.go$' || true

echo
echo "== dto outline =="
ast-grep outline relaykit/dto/openai_response.go --view expanded | sed -n '1,220p' || true

echo
echo "== dto relevant lines =="
sed -n '340,410p' relaykit/dto/openai_response.go

echo
echo "== relay handler relevant lines =="
sed -n '70,130p' relay/channel/openai/relay_responses.go

echo
echo "== references to streamResponse.Error and Response.Error =="
rg -n "streamResponse\.Error|Response\.Error|type.*error|response\.error|Error.*struct|type.*Response" relaykit relay -g '*.go' | sed -n '1,220p'

Repository: QuantumNous/new-api

Length of output: 43863


🌐 Web query:

OpenAI Responses streaming top-level error event code message param documentation

💡 Result:

When using streaming with the OpenAI API, error handling occurs both at the initiation of the request and during the stream itself. Error Structure When an API error occurs, the error object consistently includes the following fields [1][2][3]: - code: A string identifying the specific type of error (e.g., 'rate_limit_exceeded', 'invalid_request_error') [4][1][5]. - message: A human-readable string explaining the error [4][1][2]. - param: A string identifying the specific parameter that caused the error, if applicable [4][1][2]. - type: A string categorizing the error (e.g., 'invalid_request_error', 'server_error') [1][2][5]. Streaming Error Handling 1. Request Initiation: Errors that occur before the stream begins (e.g., network issues, authentication errors, or invalid initial parameters) are thrown by the initial API call [6]. These should be caught using standard try-catch blocks surrounding the request initiation [7][8][6]. 2. Streaming Events: For streaming endpoints, such as the Responses API or Chat Completions, the API can emit dedicated error events during the stream [9][4][10]. - In the Responses API, an event with the type 'error' is explicitly emitted when a response fails [4]. This event contains the code, message, and param fields [4]. - If using the OpenAI SDKs, errors during iteration should be caught within the loop that processes the stream chunks [6]. If a stream is interrupted or fails to produce a valid response, the SDK may throw an internal error (e.g., 'OpenAIError') that also requires handling [11][12]. Best Practices - Wrap your request in a try-catch block to handle initial setup errors [7][6]. - When iterating through the stream, be prepared to catch exceptions that may occur due to connection drops or premature stream termination [6][12]. - Consult the official API reference for your specific endpoint, as streaming event schemas can vary between legacy and newer (e.g., Responses) APIs [9][4][10].

Citations:


🌐 Web query:

OpenAI Responses streaming response.error event schema top-level error

💡 Result:

In OpenAI streaming responses—particularly within the Responses API and structured streaming contexts—the error event follows a specific schema designed to communicate failure states mid-stream [1][2]. The standard schema for an error event in these streams is structured as follows [1][3]: { "type": "error", "sequence_number": , "error": { "type": "", "code": "<string|null>", "message": "", "param": "<string|object|null>" } } Key components include: type: Always set to "error" to identify the event type [1]. sequence_number: An integer representing the sequence position of the event [1]. error: An object containing the details of the failure [1][3]: - type: The category or classification of the error (e.g., "invalid_request_error", "server_error") [3]. - code: A specific error code string, or null if not applicable [1][3]. - message: A human-readable description of the error [1][3]. - param: The specific parameter associated with the error, which may be a string or an object depending on the error context [1][3]. It is important to distinguish this specific "error" event schema from general API errors, which may be raised by the SDK as exceptions (e.g., APIError, BadRequestError) when the request itself fails before or during the stream [4][5][6]. When using official SDKs, you can typically listen for these events via event emitters or stream iterators (e.g., event.type == "error" or.on("error",...)) to handle terminal states gracefully [2][7][8].

Citations:


🌐 Web query:

site:platform.openai.com Responses streaming events "error" code message param

💡 Result:

In the context of OpenAI APIs and general streaming (Server-Sent Events) architectures, errors occurring after a stream has already begun are typically handled by sending a specific error event before closing the connection [1]. For APIs following the OpenAI standard, errors in asynchronous or streaming contexts are structured as objects containing a code and a message [2]. Specifically: 1. Error Structure: Error objects typically consist of a code (a machine-readable string like server_error or rate_limit_exceeded) and a message (a human-readable description of the error) [2]. 2. Streaming Behavior: When a streaming request fails, the server often sends an event containing the error details in the data field—or occasionally terminates the stream abruptly after the final chunk—depending on the specific endpoint's implementation [1]. If you are developing your own streaming API and need to convey errors, it is recommended practice to: - Use the data field of the SSE event to send a JSON-encoded object [1]. - Include a specific type field (e.g., error) to distinguish it from data chunks [1]. - Structure the payload with code and message parameters to ensure consistent error handling for your clients [2]. Always verify the specific implementation details in your API's schema or documentation, as error reporting can vary significantly between different streaming protocols and individual service designs [2][1].

Citations:


🌐 Web query:

developers.openai.com resource reference responses streaming error code message param

💡 Result:

When streaming responses from the OpenAI API, error events are communicated through specific event types. According to the official documentation for the Responses API, an error event is indicated by the type: "error" property [1][2]. The expected structure for an error event includes the following parameters [1][2]: - code: A string representing the specific error code [1][2]. - message: A string containing the error message [1][2]. - param: A string identifying the parameter that caused the error, if applicable [1][2]. - sequence_number: A number indicating the sequence of the event [1][2]. However, developers have observed that the actual API response may sometimes return these details nested within an error object (e.g., { "type": "error", "error": { "code": "...", "message": "...", "param": "..." } }) rather than at the root level as initially documented [3]. If you encounter difficulty accessing these fields, it is recommended to inspect the raw response or the Patch object (in some SDKs) to retrieve them from the nested structure [3]. When handling streaming in your application, you should listen for the error event type to identify and handle these issues programmatically [4]. Additionally, for non-streaming requests or general API interaction, the API typically returns standard error objects containing code, message, type, and param fields [5][6]. If you are using the OpenAI Python SDK, it generally maps these error responses into specific exception classes (such as RateLimitError or APIError) by parsing the JSON response body [7][6].

Citations:


🌐 Web query:

OpenAI Responses API streaming events error event structure code message param type object

💡 Result:

In the OpenAI Responses API, the streaming error event is a specific event type emitted when an error occurs during the stream [1][2]. The documented structure for an error event is as follows [1][3]: { "type": "error", "code": "string", "message": "string", "param": "string", "sequence_number": number } Field details: - type: Always set to "error" [1][3]. - code: A string representing the error code [1][3]. - message: A string containing the error message [1][3]. - param: An optional string indicating the error parameter, if applicable [1][3]. - sequence_number: A number representing the sequence number of this event [1][3]. Note: There have been reports that the API service may intermittently return a nested error structure (e.g., {"error": {"code": "...", "message": "...",...}}) [4][5], which differs from the documented top-level format. Developers should implement robust parsing that can handle both the documented format and, if necessary, the nested structure [5]. Additionally, the Responses API also utilizes a response.failed event for when a response generation specifically fails, which includes the response object itself [1][6]. This should not be confused with the general transport or stream-level error event [6].

Citations:


Handle the top-level Responses API error event payload.

type: "error" stream events can carry top-level code, message, and param, so the current streamResponse.Error fallback only handles nested response.*error payloads. Add fields/raw fallback for top-level error events and construct streamError from them before calling sr.Error(...).

📍 Affects 2 files
  • relaykit/dto/openai_response.go#L389-L389 (this comment)
  • relay/channel/openai/relay_responses.go#L99-L109
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relaykit/dto/openai_response.go` at line 389, The Responses API stream error
handling must support top-level error event fields instead of only nested
response.error payloads. In relaykit/dto/openai_response.go, extend the response
DTO around Error with top-level code, message, and param fields or an equivalent
raw fallback; in relay/channel/openai/relay_responses.go, update the stream
response handling to construct streamError from those top-level values before
calling sr.Error(...), while preserving nested-error handling.

Source: MCP tools

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: Responses terminal failures are recorded as successful EOF and preserve channel affinity

1 participant