@samitouri / QOS-React-1 / commits / 4f34cc4a2e

[Fiber] Don't throw away the Error object retaining the owner stack (#33976)

We currently throw away the Error once we've used to the owner stack of a Fiber once. This maybe helps a bit with memory and redoing it but we really don't expect most Fibers to hit this at all. It's not very hot. If we throw away the Error, then we can't use native debugger protocols to inspect the native stack. Instead, we'd have to maintain a url to resource map indefinitely like what Chrome DevTools does to map a url to a resource. Technically it's not even technically correct since the file path might not be reversible and could in theory conflict.

Sebastian Markbåge committed Jul 24, 2025 at 13:33 UTC 4f34cc4a2e1198493375867d1876509ae9771aee
3 files changed +6 -9
packages/react-devtools-shared/src/backend/fiber/DevToolsFiberComponentStack.js
+1 -1
@@ -199,7 +199,7 @@ export function getOwnerStackByFiberInDev(
199 if (typeof owner.tag === 'number') {
200 const fiber: Fiber = (owner: any);
201 owner = fiber._debugOwner;
202 - let debugStack = fiber._debugStack;
202 + let debugStack: void | null | string | Error = fiber._debugStack;
203 // If we don't actually print the stack if there is no owner of this JSX element.
204 // In a real app it's typically not useful since the root app is always controlled
205 // by the framework. These also tend to have noisy stacks because they're not rooted
packages/react-reconciler/src/ReactFiberComponentStack.js
+4 -7
@@ -177,7 +177,7 @@ export function getOwnerStackByFiberInDev(workInProgress: Fiber): string {
177 if (typeof owner.tag === 'number') {
178 const fiber: Fiber = (owner: any);
179 owner = fiber._debugOwner;
180 - let debugStack = fiber._debugStack;
180 + const debugStack = fiber._debugStack;
181 // If we don't actually print the stack if there is no owner of this JSX element.
182 // In a real app it's typically not useful since the root app is always controlled
183 // by the framework. These also tend to have noisy stacks because they're not rooted
@@ -185,12 +185,9 @@ export function getOwnerStackByFiberInDev(workInProgress: Fiber): string {
185 // if the element was created in module scope. E.g. hoisted. We could add a a single
186 // stack frame for context for example but it doesn't say much if that's a wrapper.
187 if (owner && debugStack) {
188 - if (typeof debugStack !== 'string') {
189 - // Stash the formatted stack so that we can avoid redoing the filtering.
190 - fiber._debugStack = debugStack = formatOwnerStack(debugStack);
191 - }
192 - if (debugStack !== '') {
193 - info += '\n' + debugStack;
188 + const formattedStack = formatOwnerStack(debugStack);
189 + if (formattedStack !== '') {
190 + info += '\n' + formattedStack;
191 }
192 }
193 } else if (owner.debugStack != null) {
packages/react-reconciler/src/ReactInternalTypes.js
+1 -1
@@ -200,7 +200,7 @@ export type Fiber = {
200
201 _debugInfo?: ReactDebugInfo | null,
202 _debugOwner?: ReactComponentInfo | Fiber | null,
203 - _debugStack?: string | Error | null,
203 + _debugStack?: Error | null,
204 _debugTask?: ConsoleTask | null,
205 _debugNeedsRemount?: boolean,
206