Skip to content

fix(responses): reject with OpenAIError when the stream emits an error event - #2021

Merged
HAYDEN-OAI merged 4 commits into
openai:mainfrom
morgan-coded:responses-error-frame
Aug 12, 2026
Merged

fix(responses): reject with OpenAIError when the stream emits an error event#2021
HAYDEN-OAI merged 4 commits into
openai:mainfrom
morgan-coded:responses-error-frame

Conversation

@morgan-coded

@morgan-coded morgan-coded commented Jul 26, 2026

Copy link
Copy Markdown
Contributor
  • I understand that this repository is auto-generated and my pull request may not be merged.

Summary

Fixes #2020.

  • Convert streamed Responses API failures into APIError before response accumulation or generic event emission, including errors received before response.created.
  • Preserve the error message, code, parameter, classification, and embedded retry metadata for both actual nested OpenAI/Azure error envelopes and the flat shape described by the current generated schema.
  • Reuse EventStream.events('event') so asynchronous iteration retains failures that occur while an application is processing an earlier event, drains buffered events in order, and cleans up correctly on cancellation.
  • Keep lifecycle error listeners typed as OpenAIError and preserve normal response.failed snapshot handling.

Verification

  • Added coverage for nested and flat errors, initial errors, serialized replay, actual SSE transport, request IDs, delayed iteration, buffered events, iteration after completion, and early cancellation.
  • Full handwritten suite: 1,701 tests passing.
  • Repository lint and Node.js version-policy validation passed.
  • Source and published-package type checks passed with TypeScript 6 and TypeScript 4.9.
  • Complete CommonJS/ESM package build and Bedrock import smoke tests passed.

@morgan-coded
morgan-coded requested a review from a team as a code owner July 26, 2026 18:23

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

ℹ️ 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/lib/responses/ResponseStream.ts Outdated
Comment thread src/lib/responses/ResponseStream.ts Outdated

@jbeckwith-oai jbeckwith-oai 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.

The conversion is still incomplete in two valid consumption paths:

  1. #addEvent calls accumulateResponse() before checking event.type, so an error frame sent before response.created never reaches the new branch. It still rejects with the accumulator's generic OpenAIError and loses the server message/code/param. Please convert error frames before snapshot accumulation and add coverage for an initial error frame.

  2. The raw error frame is emitted through the generic event channel before the APIError is thrown, while ResponseStream[Symbol.asyncIterator] only rejects reads that are pending at the instant the error fires and does not retain the failure. A normal for await consumer therefore observes [response.created, error] and then completes cleanly; only a separate finalResponse() call sees the APIError. Please make async iteration reject consistently (the failure-retention pattern in EventStream.events() is a useful model) and add a regression test.

Validation at c34bfea5d94941e37038bb6ac8834240f84590c4: the focused ResponseStream suite passed (6/6), Prettier and ESLint passed on changed files, TypeScript checking passed, the package build passed, and git diff --check passed. I also reproduced both cases against the built package.

@morgan-coded

Copy link
Copy Markdown
Contributor Author

Reproduced both stream-error paths against the built package and fixed them in the same order.

  1. Moved the error conversion before snapshot accumulation and generic event emission, so an initial error frame now rejects with an APIError carrying the server's message, code, and param. The regression failed at c34bfea5 with Expected constructor: APIError / Received constructor: OpenAIError, then passed on the revision.
  2. Retained async-iterator failures using EventStream.events()'s queued-event-first, one-time rejection pattern, so for await rejects even when no read was pending when the error fired. The regression failed at c34bfea5 with Received promise resolved instead of rejected / Resolved to value: undefined, then passed on the revision.

The focused ResponseStream file passes 8/8; ./scripts/lint and ./scripts/build pass; the full ./scripts/test passes 120 suites, 1465 tests, and 64 snapshots, with one suite and one test skipped.

…sponse-stream-errors

# Conflicts:
#	src/lib/responses/ResponseStream.ts
#	tests/lib/ResponseStream.test.ts
@HAYDEN-OAI
HAYDEN-OAI dismissed jbeckwith-oai’s stale review August 12, 2026 04:04

Superseded by verified commit 25e9f9c: initial nested/flat errors are converted before accumulation, generic error frames are not emitted, and async iteration retains failures through EventStream.events. Focused live-SSE/replay regressions and all 1,701 unit tests pass.

@HAYDEN-OAI HAYDEN-OAI 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.

Validated against the actual first-party/Azure nested SSE error contract and the documented flat compatibility shape. Errors are normalized before accumulation, API metadata and request IDs are preserved, and async iteration reuses EventStream.events to retain delayed failures. Verified 1,701 unit tests, focused live-SSE/replay/cancellation cases, lint, TypeScript 4.9/6 published checks, and full CJS/ESM build.

@HAYDEN-OAI
HAYDEN-OAI enabled auto-merge August 12, 2026 04:09
@HAYDEN-OAI
HAYDEN-OAI added this pull request to the merge queue Aug 12, 2026
Merged via the queue into openai:main with commit a54014d Aug 12, 2026
14 checks passed
@openai-sdks openai-sdks Bot mentioned this pull request Aug 12, 2026
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.

ResponseStream rejects with a plain object when the API emits an error event

3 participants