React 19.2 DEV-build crashes the entire fiber-tree (Should not already be working) when a component receives a cross-origin Window object (e.g. iframe.contentWindow of an iframe with srcdoc="") as a prop. The new logComponentRender (called from commitPassiveMountOnFiber) recursively walks props in addObjectToProperties / addValueToProperties and reads value.$$typeof without try/catch. For a cross-origin Window any property access throws SecurityError, corrupting the work-in-progress fiber.
This is not the React DevTools extension issue (#29011) — logComponentRender is part of the native DEV-build performance logger introduced in 19.2. It runs unconditionally in development, without any browser extension.
React version: 19.2.5 (react@19.2.5, react-dom@19.2.5)
Steps To Reproduce
- Bootstrap a fresh Vite + React 19.2.5 app:
npm create vite@latest -- --template react-ts, then install react@19.2.5 and react-dom@19.2.5.
- Replace
App.tsx with the code from the Link to code example section below.
- Run
npm run dev and open the page in Chrome (any recent version).
- Right after mount the page freezes — clicks and inputs do nothing.
- Open DevTools console and see two errors stacked:
Uncaught SecurityError: Failed to read a named property '$$typeof' from 'Window' at logComponentRender → commitPassiveMountOnFiber
Uncaught Error: Should not already be working. at performWorkOnRoot
Reproduces 100% in DEV-build. Production build (npm run build && npm run preview) is unaffected.
Link to code example
import { useEffect, useRef, useState } from 'react';
function App() {
const iframeRef = useRef<HTMLIFrameElement>(null);
const [win, setWin] = useState<Window | null>(null);
useEffect(() => {
// iframe with srcdoc="" gets origin "null" — cross-origin to host page
setWin(iframeRef.current?.contentWindow ?? null);
}, []);
return (
<>
<iframe ref={iframeRef} srcDoc="<p>hi</p>" title="x" />
{/* Pass cross-origin Window as a prop. React DEV-build's
logComponentRender walks props of <Child> and reads
win.$$typeof → SecurityError. */}
<Child win={win} />
</>
);
}
function Child({ win }: { win: Window | null }) {
return <div>{win ? 'has window' : 'no window'}</div>;
}
export default App;
The current behavior
addObjectToProperties in react-dom/cjs/react-dom-client.development.js (around line 3783) does an unguarded for (var key in object) loop, then addValueToProperties (around line 3789) reads value.$$typeof without try/catch. For a cross-origin Window any property access throws SecurityError, which propagates out of the commit phase and leaves the work-in-progress fiber broken. All subsequent renders throw Should not already be working, and the UI becomes completely unresponsive — no clicks, no input.
Stack:
Uncaught SecurityError: Failed to read a named property '$$typeof' from 'Window':
Blocked a frame with origin "http://localhost:5173" from accessing a cross-origin frame.
at addObjectToProperties (react-dom-client.development.js)
at addValueToProperties
at addObjectToProperties
at addValueToProperties
at addObjectDiffToProperties
at logComponentRender
at commitPassiveMountOnFiber
at recursivelyTraversePassiveMountEffects
Uncaught Error: Should not already be working.
at performWorkOnRoot
at performWorkOnRootViaSchedulerTask
Real-world impact: embedded notebook editors, dashboards, and preview-style tooling that store DOM or Window refs in component state (Plotly, Vega, marimo HTML widgets, Jupyter widget conversions) fail to render after first mount. The error message is misleading — the root cause is React's render-logger, not user code.
The expected behavior
addObjectToProperties and addValueToProperties should wrap property access in try/catch and treat unreadable values as an opaque marker (e.g. [CrossOriginFrame]), so the render-logger never throws. The render-logger is a DEV-only diagnostic and must not corrupt the fiber tree when iterating props.
A working workaround: wrap the body of addObjectToProperties in try/catch. Verified by patching the pre-bundled chunk via an esbuild plugin in a Vite app — fixes all symptoms in DEV without touching the rest of the build.
Related issues (different root cause but similar symptom):
React 19.2 DEV-build crashes the entire fiber-tree (
Should not already be working) when a component receives a cross-origin Window object (e.g.iframe.contentWindowof an iframe withsrcdoc="") as a prop. The newlogComponentRender(called fromcommitPassiveMountOnFiber) recursively walks props inaddObjectToProperties/addValueToPropertiesand readsvalue.$$typeofwithout try/catch. For a cross-origin Window any property access throwsSecurityError, corrupting the work-in-progress fiber.This is not the React DevTools extension issue (#29011) —
logComponentRenderis part of the native DEV-build performance logger introduced in 19.2. It runs unconditionally in development, without any browser extension.React version: 19.2.5 (
react@19.2.5,react-dom@19.2.5)Steps To Reproduce
npm create vite@latest -- --template react-ts, then installreact@19.2.5andreact-dom@19.2.5.App.tsxwith the code from the Link to code example section below.npm run devand open the page in Chrome (any recent version).Uncaught SecurityError: Failed to read a named property '$$typeof' from 'Window'atlogComponentRender→commitPassiveMountOnFiberUncaught Error: Should not already be working.atperformWorkOnRootReproduces 100% in DEV-build. Production build (
npm run build && npm run preview) is unaffected.Link to code example
The current behavior
addObjectToPropertiesinreact-dom/cjs/react-dom-client.development.js(around line 3783) does an unguardedfor (var key in object)loop, thenaddValueToProperties(around line 3789) readsvalue.$$typeofwithout try/catch. For a cross-origin Window any property access throwsSecurityError, which propagates out of the commit phase and leaves the work-in-progress fiber broken. All subsequent renders throwShould not already be working, and the UI becomes completely unresponsive — no clicks, no input.Stack:
Real-world impact: embedded notebook editors, dashboards, and preview-style tooling that store DOM or Window refs in component state (Plotly, Vega, marimo HTML widgets, Jupyter widget conversions) fail to render after first mount. The error message is misleading — the root cause is React's render-logger, not user code.
The expected behavior
addObjectToPropertiesandaddValueToPropertiesshould wrap property access in try/catch and treat unreadable values as an opaque marker (e.g.[CrossOriginFrame]), so the render-logger never throws. The render-logger is a DEV-only diagnostic and must not corrupt the fiber tree when iterating props.A working workaround: wrap the body of
addObjectToPropertiesin try/catch. Verified by patching the pre-bundled chunk via an esbuild plugin in a Vite app — fixes all symptoms in DEV without touching the rest of the build.Related issues (different root cause but similar symptom):