Conversation
`encodeReply` throws "React Element cannot be passed to Server Functions from the Client without a temporary reference set" when a React element is the root value of a `serializeModel` call (either passed directly or resolved from a promise), even when a temporary reference set is provided. The cause is that `resolveToJSON` hits the `REACT_ELEMENT_TYPE` switch case before reaching the `existingReference`/`modelRoot` check that regular objects benefit from. The synthetic JSON root created by `JSON.stringify` is never tracked in `writtenObjects`, so `parentReference` is `undefined` and the code falls through to the throw. This adds a `modelRoot` check in the `REACT_ELEMENT_TYPE` case, following the same pattern used for promises and plain objects. The added `JSX as root model` test also uncovered a pre-existing crash in the Flight Client: when the JSX element round-trips back, it arrives as a frozen object (client-created elements are frozen in DEV), and `Object.defineProperty` for `_debugInfo` fails because frozen objects are non-configurable. The same crash can occur with JSX exported as a client reference. For now, we're adding `!Object.isFrozen()` guards in `moveDebugInfoFromChunkToInnerValue` and `addAsyncInfo` to prevent the crash, which means debug info is silently dropped for frozen elements. The proper fix would likely be to clone the element so each rendering context gets its own mutable copy with correct debug info. closes #34984 closes #35690
…35731) When using a partial prerender stream, i.e. a prerender that is intentionally aborted before all I/O has resolved, consumers of `createFromReadableStream` would need to keep the stream unclosed to prevent React Flight from erroring on unresolved chunks. However, some browsers (e.g. Chrome, Firefox) keep unclosed ReadableStreams with pending reads as native GC roots, retaining the entire Flight response. With this PR we're adding an `unstable_allowPartialStream` option, that allows consumers to close the stream normally. The Flight Client's `close()` function then transitions pending chunks to halted instead of erroring them. Halted chunks keep Suspense fallbacks showing (i.e. they never resolve), and their `.then()` is a no-op so no new listeners accumulate. Inner stream chunks (ReadableStream/AsyncIterable) are closed gracefully, and `getChunk()` returns halted chunks for new IDs that are accessed after closing the response. Blocked chunks are left alone because they may be waiting on client-side async operations like module loading, or on forward references to chunks that appeared later in the stream, both of which resolve independently of closing.
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )