react/react · error · Error

DevTools tooltip root node not found: can't display the cont

Error message

DevTools tooltip root node not found: can't display the context menu

What it means

useContextMenu queries the document for [data-react-devtools-portal-root] on every contextmenu event so the menu can be portaled into it. If that node is absent the menu has nowhere to mount, so it throws. The portal root is injected by the DevTools shell (browser extension content script, standalone, or Fusebox inline).

Source

Thrown at packages/react-devtools-shared/src/devtools/ContextMenu/useContextMenu.js:50

  }, []);

  useEffect(() => {
    const anchor = anchorElementRef.current;
    if (anchor == null) return;

    function handleAnchorContextMenu(e: MouseEvent) {
      e.preventDefault();
      e.stopPropagation();

      const {pageX, pageY} = e;

      const ownerDocument = anchor?.ownerDocument;
      const portalContainer = ownerDocument?.querySelector(
        '[data-react-devtools-portal-root]',
      );

      if (portalContainer == null) {
        throw new Error(
          "DevTools tooltip root node not found: can't display the context menu",
        );
      }

      // `x` and `y` should be relative to the container, to which these context menus will be portaled
      // we can't use just `pageX` or `pageY` for Fusebox integration, because RDT frontend is inlined with the whole document
      // meaning that `pageY` will have an offset of 27, which is the tab bar height
      // for the browser extension, these will equal to 0
      const {top: containerTop, left: containerLeft} =
        portalContainer.getBoundingClientRect();

      setShouldShow(true);
      setPosition({x: pageX - containerLeft, y: pageY - containerTop});
    }

    anchor.addEventListener('contextmenu', handleAnchorContextMenu);
    return () => {
      anchor.removeEventListener('contextmenu', handleAnchorContextMenu);

View on GitHub (pinned to 22e4f993c7)

Solutions

  1. Ensure the DevTools shell renders <div data-react-devtools-portal-root /> into the host document before any context menu can open.
  2. If embedding DevTools yourself, add the portal root node to ownerDocument.body and keep it mounted for the session.
  3. Gate the contextmenu listener on the portal root existing.

Example fix

// before — embedding without a portal root
// (menu throws on right-click)

// after — inject the portal root the DevTools shell expects
const root = document.createElement('div');
root.setAttribute('data-react-devtools-portal-root', '');
document.body.appendChild(root);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the DevTools portal root exists before the menu can open.
function ensurePortalRoot(doc) {
  let node = doc.querySelector('[data-react-devtools-portal-root]');
  if (!node) {
    node = doc.createElement('div');
    node.setAttribute('data-react-devtools-portal-root', '');
    doc.body.appendChild(node);
  }
  return node;
}

Prevention

When it happens

Trigger: Right-clicking an anchor element after the DevTools portal root was removed from the DOM, or before the DevTools shell has injected it.

Common situations: DevTools shell not finished initialising when the user right-clicks; a custom DevTools embedding that forgot to render <div data-react-devtools-portal-root />; Fusebox/inline integration where the portal node was unmounted with the panel.

Related errors


AI-assisted analysis of react/react@22e4f993c7 (2026-08-12). Data as JSON: /api/errors/7ceabaaedf203294. Report an issue: GitHub.