[Flight] Avoid main-thread stalls from large debug strings#36570
Merged
Conversation
When the React Flight Server serializes a very large string (multiple megabytes) as part of the debug info for a Server Component — the resolved value of an awaited I/O Promise, a replayed `console.log` argument, props, etc. — two places in the client stalled the main thread: - The Flight Client's parser synchronously decodes the entire string while reading the debug chunk. - React DevTools' performance tracks then `JSON.stringify` the same value to build a property description, and Chrome's tracing UI does not handle multi-megabyte description strings gracefully. Every debug string flows through the string branch of `renderDebugModel` — console arguments via `emitConsoleChunk`, awaited values and other Promise-resolved values via `emitOutlinedDebugModelChunk`. So this caps it there: strings longer than 1,000,000 characters are omitted and replaced with a short placeholder that states how long the original string was, in the spirit of the existing `OMITTED_PROP_ERROR`. Handling it in this one spot covers every source with a single check. As a second layer of defense, `addValueToProperties` in `ReactPerformanceTrackProperties` truncates string descriptions to 1023 characters plus an ellipsis before `JSON.stringify`. This prevents Chrome DevTools from blocking the main thread on the description and then bailing out of showing the performance track spans entirely. 1023 mirrors the existing "large string" boundary the Flight server uses when serializing text (values 1024 and longer are outlined via `serializeLargeTextString`). This truncation only affects the performance track description; the full value (below the 1 MB server cap) is still shown in the Suspense and Components panels under "suspended by" and "props".
|
Comparing: 6b5ea12...6a44d94 Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: (No significant changes) |
Use a prop instead of console.log replaying.
eps1lon
approved these changes
May 29, 2026
eps1lon
approved these changes
May 29, 2026
github-actions Bot
pushed a commit
to code/lib-react
that referenced
this pull request
May 31, 2026
…36570) DiffTrain build for [f0dfee3](facebook@f0dfee3)
github-actions Bot
pushed a commit
to code/lib-react
that referenced
this pull request
May 31, 2026
…36570) DiffTrain build for [f0dfee3](facebook@f0dfee3)
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.
When the React Flight Server serializes a very large string (multiple megabytes) as part of the debug info for a Server Component — the resolved value of an awaited I/O Promise, a replayed
console.logargument, props, etc. — two places in the client stalled the main thread:JSON.stringifythe same value to build a property description, and Chrome's tracing UI does not handle multi-megabyte description strings gracefully.Every debug string flows through the string branch of
renderDebugModel— console arguments viaemitConsoleChunk, awaited values and other Promise-resolved values viaemitOutlinedDebugModelChunk. So this caps it there: strings longer than 1,000,000 characters are omitted and replaced with a short placeholder that states how long the original string was, in the spirit of the existingOMITTED_PROP_ERROR. Handling it in this one spot covers every source with a single check.As a second layer of defense,
addValueToPropertiesinReactPerformanceTrackPropertiestruncates string descriptions to 1023 characters plus an ellipsis beforeJSON.stringify. This prevents Chrome DevTools from blocking the main thread on the description and then bailing out of showing the performance track spans entirely. 1023 mirrors the existing "large string" boundary the Flight server uses when serializing text (values 1024 and longer are outlined viaserializeLargeTextString). This truncation only affects the performance track description; the full value (below the 1 MB server cap) is still shown in the Suspense and Components panels under "suspended by" and "props".