Skip to content

fix(fetch): release the event iterator when an event fails to serialize - #112

Merged
dinwwwh merged 1 commit into
mainfrom
claude/event-stream-error-handling-e22e36
Sep 26, 2026
Merged

dinwwwh merged 1 commit into
mainfrom
claude/event-stream-error-handling-e22e36

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Sep 26, 2026

Copy link
Copy Markdown
Member

toEventStream now closes the source generator when a yielded value can't be serialized (BigInt, circular object, throwing toJSON). Before this, the stream errored but the generator stayed paused at its yield and its finally never ran. Anything it held stayed open: subscriptions, handles, timers, locks. The node, fastify and aws-lambda adapters are fixed too, since they use the fetch implementation.

Fixes

  • The generator's finally now runs when an event fails to serialize. Previously an errored stream never called cancel(), and cancel() was the only place that called iterator.return().
  • The stream still errors with the original serialization error, even if the generator's own cleanup throws.
  • No change when the generator throws, returns, or the client disconnects. ErrorEvents are still sent as error events.

Testing

  • New tests for BigInt, circular and throwing-toJSON values check that cleanup runs. All three fail without the fix.
  • New test checks that the serialization error wins when cleanup also throws.
  • fetch, node, fastify and aws-lambda test suites pass (276 tests); type:check and lint are clean.

When a yielded value could not be serialized (BigInt, circular object,
throwing toJSON), toEventStream errored the stream without calling
iterator.return(). An errored ReadableStream never invokes cancel(), so
the source generator stayed suspended at its yield and its finally block
never ran, leaking whatever it held. The node, fastify and aws-lambda
adapters inherited this through the fetch implementation.

Serialization failures are now handled separately from iterator errors:
the suspended iterator is released first, then the stream is errored
with the original serialization error.
@pkg-pr-new

pkg-pr-new Bot commented Sep 26, 2026

Copy link
Copy Markdown
@standard-server/aws-lambda

npm i https://pkg.pr.new/@standard-server/aws-lambda@112

@standard-server/core

npm i https://pkg.pr.new/@standard-server/core@112

@standard-server/fastify

npm i https://pkg.pr.new/@standard-server/fastify@112

@standard-server/fetch

npm i https://pkg.pr.new/@standard-server/fetch@112

@standard-server/node

npm i https://pkg.pr.new/@standard-server/node@112

@standard-server/peer

npm i https://pkg.pr.new/@standard-server/peer@112

@standard-server/shared

npm i https://pkg.pr.new/@standard-server/shared@112

commit: d189ea1

@codecov

codecov Bot commented Sep 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

  • Release the iterator on serialization failure — toEventStream's pull now wraps serialization in its own try, and on a throw runs await iterator.return?.() (when the result isn't done) before erroring the stream, so the source generator's finally actually executes.
  • Error precedence preserved — the cleanup call sits in a try whose finally calls controller.error(err), so the original serialization error wins even when cleanup itself throws; the cleanup rejection is absorbed by the already-errored stream.
  • Shared adapters covered — node, fastify and aws-lambda inherit the fetch implementation (packages/node/src/event-stream.ts re-exports it), so no duplicate copy of pull needed the same fix. The peer transmitter already cancels on send failure and is untouched.
  • Regression tests — three it.each cases (BigInt, circular reference, throwing toJSON) assert the generator's finally runs and the read rejects; verified discriminating by reverting the impl to the parent, where all three fail (hasFinally is false).

Pullfrog  | View workflow run | Using DeepSeek Flash (default — pick a model for stronger reviews) | 𝕏

@codspeed

codspeed Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 26 untouched benchmarks
⏩ 108 skipped benchmarks1


Comparing claude/event-stream-error-handling-e22e36 (d189ea1) with main (3738f90)

Open in CodSpeed

Footnotes

  1. 108 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@dinwwwh
dinwwwh merged commit e5eb0aa into main Sep 26, 2026
11 checks passed
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