@samitouri / QOS-React / commits / aad7c664ff

[Flight] Don't try to close debug channel twice (#34340)

When the debug channel was already closed, we must not try to close it again when the Response gets garbage collected. **Test plan:** 1. reduce the Flight fixture `App` component to a minimum [^1] - remove everything from `<body>` - delete the `console.log` statement 2. open the app in Firefox (seems to have a more aggressive GC strategy) 3. wait a few seconds On `main`, you will see the following error in the browser console: ``` TypeError: Can not close stream after closing or error ``` With this change, the error is gone. [^1]: It's a bit concerning that step 1 is needed to reproduce the issue. Either GC is behaving differently with the unmodified App, or we may hold on to the Response under certain conditions, potentially creating a memory leak. This needs further investigation.

Hendrik Liebau committed Aug 29, 2025 at 17:22 UTC aad7c664ffbde52e5d8004b542d83d6d4b7a32a0
1 file changed +8 -3
packages/react-client/src/ReactFlightClient.js
+8 -3
@@ -1010,10 +1010,15 @@ export function reportGlobalError(
1010 if (__DEV__) {
1011 const debugChannel = response._debugChannel;
1012 if (debugChannel !== undefined) {
1013 - // If we don't have any more ways of reading data, we don't have to send any
1014 - // more neither. So we close the writable side.
1013 + // If we don't have any more ways of reading data, we don't have to send
1014 + // any more neither. So we close the writable side.
1015 closeDebugChannel(debugChannel);
1016 response._debugChannel = undefined;
1017 + // Make sure the debug channel is not closed a second time when the
1018 + // Response gets GC:ed.
1019 + if (debugChannelRegistry !== null) {
1020 + debugChannelRegistry.unregister(response);
1021 + }
1022 }
1023 }
1024 }
@@ -2434,7 +2439,7 @@ function ResponseInstance(
2439 // When a Response gets GC:ed because nobody is referring to any of the
2440 // objects that lazily load from the Response anymore, then we can close
2441 // the debug channel.
2437 - debugChannelRegistry.register(this, debugChannel);
2442 + debugChannelRegistry.register(this, debugChannel, this);
2443 }
2444 }
2445 }