captureOwnerStack

Canary

The captureOwnerStack API is currently only available in React’s Canary and experimental channels. Learn more about React’s release channels here.

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 (outside of render, Effects, Events and React error handlers), it returns an empty string (see Troubleshooting: The Owner Stack is empty). Outside of development builds, null is returned (see Troubleshooting: The Owner Stack is null).

Caveats

  • Owner Stacks are only available in development. captureOwnerStack will always return null outside of development.
Deep Dive

Owner Stack vs Component Stack

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 App

However, the Owner Stack would only read

at Component

Neither 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

Improve error reporting

Check out the following example to see how to use captureOwnerStack to improve error reporting:

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, after a fetch or in a custom DOM event handler. During render, Effects, Events, and React error handlers (e.g. hydrateRoot#options.onCaughtError) Owner Stacks should be available.

In the example below, clicking the button will log an empty Owner Stack because captureOwnerStack was called during a custom DOM event handler. The Owner Stack must be captured earlier e.g. by moving the call of captureOwnerStack into the Effect body.

import {captureOwnerStack, useEffect} from 'react';

export default function App() {
  useEffect(() => {
    function handleEvent() {
      console.log('Owner Stack: ', captureOwnerStack());
    }

    document.addEventListener('click', handleEvent);

    return () => {
      document.removeEventListener('click', handleEvent);
    }
  })

  return <button>Click me to see that Owner Stacks are not available in custom DOM event handlers</button>;
}