captureOwnerStack
captureOwnerStack reads the current Owner Stack in development and returns it as a string if available.
const stack = captureOwnerStack();Reference
captureOwnerStack()
Call captureOwnerStack to get the current Owner Stack.
import {captureOwnerStack} from 'react';
function Component() {
if (process.env.NODE_ENV !== 'production') {
const ownerStack = captureOwnerStack();
console.log(ownerStack);
}
}Parameters
captureOwnerStack does not take any parameters.
Returns
captureOwnerStack returns string | null.
If no Owner Stack is available, it returns an empty string.
Outside of development builds, null is returned.
Caveats
- Owner Stacks are only available in development.
captureOwnerStackwill always returnnulloutside of development.
Deep Dive
The Owner Stack is different from the Component Stack available in React error handlers like errorInfo.componentStack in onUncaughtError.
For example, consider the following code:
import {captureOwnerStack} from 'react'; import {createRoot} from 'react-dom/client'; import App, {Component} from './App.js'; import './styles.css'; createRoot(document.createElement('div'), { onUncaughtError: (error, errorInfo) => { // The stacks are logged instead of showing them in the UI directly to highlight that browsers will apply sourcemaps to the logged stacks. // Note that sourcemapping is only applied in the real browser console not in the fake one displayed on this page. console.log(errorInfo.componentStack); console.log(captureOwnerStack()); }, }).render( <App> <Component label="disabled" /> </App> );
SubComponent would throw an error.
The Component Stack of that error would be
at SubComponent
at fieldset
at Component
at main
at React.Suspense
at AppHowever, the Owner Stack would only read
at ComponentNeither App nor the DOM components (e.g. fieldset) are considered Owners in this Stack since they didn’t contribute to “creating” the node containing SubComponent. App and DOM components only forwarded the node. App just rendered the children node as opposed to Component which created a node containing SubComponent via <SubComponent />.
Neither Navigation nor legend are in the stack at all since it’s only a sibling to a node containing <SubComponent />.
SubComponent is omitted because it’s already part of the callstack.
Usage
Show an error dialog
Check out the following example to see how to use captureOwnerStack to improve an error dialog:
- createRoot usage: Show a dialog for uncaught errors
- createRoot usage: Displaying Error Boundary errors
- createRoot usage: Displaying a dialog for recoverable errors
Expanding error stacks
In addition to the stack trace of the error itself, you can use captureOwnerStack to append the Owner Stack.
This can help trace the error especially when the error is caused by props. The Owner Stack helps trace the flow of props.
import {captureOwnerStack} from 'react'; import {createRoot} from 'react-dom/client'; import App from './App.js'; import './styles.css'; const root = createRoot(document.getElementById('root'), { onUncaughtError: (error, errorInfo) => { if (process.env.NODE_ENV !== 'production') { const ownerStack = captureOwnerStack(); error.stack = // The stack is only split because these sandboxes don't implement ignore-listing 3rd party frames via sourcemaps. // A framework would ignore-list stackframes from React via sourcemaps and then you could just `error.stack += ownerStack`. // To learn more about ignore-listing see https://developer.chrome.com/docs/devtools/x-google-ignore-list error.stack.split('\n at react-stack-bottom-frame')[0] + ownerStack; } // The stacks are logged instead of showing them in the UI directly to highlight that browsers will apply sourcemaps to the logged stacks. // Note that sourcemapping is only applied in the real browser console not in the fake one displayed on this page. console.error('Uncaught', error); }, }).render(<App />);
Troubleshooting
The Owner Stack is null
captureOwnerStack was called outside of development builds.
For performance reasons, React will not keep track of Owners in production.
The Owner Stack is empty
The call of captureOwnerStack happened outside of a React controlled function e.g. in a setTimeout callback.
During render, Effects, Events, and React error handlers (e.g. hydrateRoot#options.onCaughtError) Owner Stacks should be available.