fix(fetch): release the event iterator when an event fails to serialize - #112
Merged
Merged
Conversation
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.
@standard-server/aws-lambda
@standard-server/core
@standard-server/fastify
@standard-server/fetch
@standard-server/node
@standard-server/peer
@standard-server/shared
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Release the iterator on serialization failure —
toEventStream'spullnow wraps serialization in its owntry, and on a throw runsawait iterator.return?.()(when the result isn't done) before erroring the stream, so the source generator'sfinallyactually executes. - Error precedence preserved — the cleanup call sits in a
trywhosefinallycallscontroller.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.tsre-exports it), so no duplicate copy ofpullneeded the same fix. The peer transmitter already cancels on send failure and is untouched. - Regression tests — three
it.eachcases (BigInt, circular reference, throwingtoJSON) assert the generator'sfinallyruns and the read rejects; verified discriminating by reverting the impl to the parent, where all three fail (hasFinallyisfalse).
DeepSeek Flash (default — pick a model for stronger reviews) | 𝕏
Contributor
Merging this PR will not alter performance
Comparing Footnotes
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

toEventStreamnow closes the source generator when a yielded value can't be serialized (BigInt, circular object, throwingtoJSON). Before this, the stream errored but the generator stayed paused at itsyieldand itsfinallynever 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
finallynow runs when an event fails to serialize. Previously an errored stream never calledcancel(), andcancel()was the only place that callediterator.return().ErrorEvents are still sent aserrorevents.Testing
toJSONvalues check that cleanup runs. All three fail without the fix.type:checkand lint are clean.