@samitouri / QOS-React / commits / f3a803617e

[Flight] Ensure async info owners are outlined properly (#34465)

When we emit objects of type `ReactAsyncInfo`, we need to make sure that their owners are outlined, using `outlineComponentInfo`. Otherwise we would end up accidentally emitting stashed fields that are not part of the transport protocol, specifically `debugStack`, `debugTask`, and `debugLocation`. This would lead to runtime errors in the client, when for example, the stack for a `debugLocation` is processed in `buildFakeCallStack`, but the stack was actually omitted from the RSC payload, because for those fields we don't ensure that the object limit is increased by the length of the stack, as we do when we're emitting the `stack` of a `ReactComponentInfo` object in `outlineComponentInfo`.

Hendrik Liebau committed Sep 11, 2025 at 18:10 UTC f3a803617ec4ba9d14bf5205ffece28ed1496a1d
1 file changed +9
packages/react-server/src/ReactFlightServer.js
+9
@@ -2384,6 +2384,11 @@ function visitAsyncNode(
2384 // Promise that was ultimately awaited by the user space await.
2385 serializeIONode(request, ioNode, awaited.promise);
2386
2387 + // Ensure the owner is already outlined.
2388 + if (node.owner != null) {
2389 + outlineComponentInfo(request, node.owner);
2390 + }
2391 +
2392 // We log the environment at the time when the last promise pigned ping which may
2393 // be later than what the environment was when we actually started awaiting.
2394 const env = (0, request.environmentName)();
@@ -5133,6 +5138,10 @@ function forwardDebugInfo(
5138 } else {
5139 // Outline the IO info in case the same I/O is awaited in more than one place.
5140 outlineIOInfo(request, ioInfo);
5141 + // Ensure the owner is already outlined.
5142 + if (info.owner != null) {
5143 + outlineComponentInfo(request, info.owner);
5144 + }
5145 // We can't serialize the ConsoleTask/Error objects so we need to omit them before serializing.
5146 let debugStack;
5147 if (info.stack == null && info.debugStack != null) {