Repository navigation
fix(web): fail renders on late default serializer errors - #4650
everton-dgn wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 6707995 The changes in this PR will be included in the next version bump. This PR includes changesets to release 15 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Merging this PR will degrade performance by 7.76%3 warnings
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
…reject the key after Ryan's ruling on #4659 (2026-11-03): "failing ssr on failed serialization feels reasonable otherwise we could be midstream." everton-dgn's #4650 (cherry-picked in the previous commit) fails the render on a late default serializer failure. Limit that to failures before the first flush (an awaited render, or a stream whose shell has not gone out yet, checked again where the shell is about to be written), and keep the client-side rejection of the key for failures after it, where the render completes. Merges the two stream-async-serialize-failure-4647 specs (pre-flush cases from #4650, midstream cases from #4659, plus a boundary value that fails while the shell still waits on a blocker). Re-pins the #4242 writer case: its failure lands before the shell, so the render fails. Updates the `handling: "serialize"` contract in 12-ssr-http.md, the renderToStream onError JSDoc, the serializer comment and both changesets. Co-authored-by: Éverton Toffanetto <evertondgn@hotmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117BoWNSSgtemsSYsaX2hXE
…#4647) (#4659) * fix(web): reject a hydration key whose async value fails to serialize (#4647) An async value that resolved to something seroval cannot serialize was reported as `render/serialize` and the render completed, but the payload declared the key's promise and never settled it, so the client's read stayed pending forever. Per Ryan's ruling (2026-11-03), the hydration serializer now rejects that promise with an error that says it is a serialization failure and names the key. The hydrating read throws into the nearest Errored, whose fallback replaces the server's content until reset() or an input change reruns it as a client fetch. Server-only: the change is in the hydration serializer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117BoWNSSgtemsSYsaX2hXE * fix(web): fail renders on late default serializer errors * fix(web): split #4647 at the first flush: fail the render before it, reject the key after Ryan's ruling on #4659 (2026-11-03): "failing ssr on failed serialization feels reasonable otherwise we could be midstream." everton-dgn's #4650 (cherry-picked in the previous commit) fails the render on a late default serializer failure. Limit that to failures before the first flush (an awaited render, or a stream whose shell has not gone out yet, checked again where the shell is about to be written), and keep the client-side rejection of the key for failures after it, where the render completes. Merges the two stream-async-serialize-failure-4647 specs (pre-flush cases from #4650, midstream cases from #4659, plus a boundary value that fails while the shell still waits on a blocker). Re-pins the #4242 writer case: its failure lands before the shell, so the render fails. Updates the `handling: "serialize"` contract in 12-ssr-http.md, the renderToStream onError JSDoc, the serializer comment and both changesets. Co-authored-by: Éverton Toffanetto <evertondgn@hotmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117BoWNSSgtemsSYsaX2hXE * fix(web): reject everything a midstream-failed write sent, not just its key (#4647) - Move the rejection into an exported `rejectUnserializedKey`, passed only by `renderToStream` as the hydration serializer's `late` (so `renderToString` does not carry it), and drop the dead `started` flag. - On a write that fails after the first flush, reject every promise and throw into every stream that write already sent (a nested promise, an async iterable's later items), not only a top-level thenable key. - Drop the failed parse's indexes from the shared refs, so a second key on the same value parses it again and rejects instead of resolving `undefined` from a slot the client never filled. - Hydration spec replays real recorded stream output (errored-unserializable-4647.gen.spec.tsx) instead of a hand-written payload. - Docs: the serialize road's wire (a fixed message naming the key, all builds); pins cite the dated maintainer ruling (2026-11-03). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117BoWNSSgtemsSYsaX2hXE --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Éverton Toffanetto <evertondgn@hotmail.com>
|
Thanks, Éverton. Ryan ruled for this split: an unserializable value fails the render before the first flush and rejects its key on the client after it. Your commit landed with your authorship in #4659 (5ae39fc), so I am closing this draft as folded in. Generated by Claude Code |
Summary
Refs #4647 (Solid 2,
next). Draft for the render-failure option proposed in the issue.With the default serializer, an async value can fail after
writereturns, yet the render reports completion. Track that failure and finish through the existing failure path, withoutonCompleteAll. Synchronous failures and custom serializers retain their behavior. Buffered stream failures reported insidewriteremain outside this change.This discards the document before the shell, including otherwise valid siblings. After the shell, the response ends with the HTML already sent; the client key remains pending. Rejecting that key instead would require a serializer change. The three updated expectations make this tradeoff explicit.
How did you test this change?
--concurrency=1.