Skip to content

React 19 hydration crash in CopyHostStyles - useFrame() returns null document #1562

@mosaicws

Description

@mosaicws

Title

CopyHostStyles crashes with "Cannot read properties of null (reading 'document')" during React 19 hydration


Description

The CopyHostStyles component crashes during React 19 hydration with "Cannot read properties of null (reading 'document')". The error occurs intermittently when the Puck editor is rendered in a Next.js 16 app with React 19, particularly during the reconnectPassiveEffects hydration phase.

The root cause is that useFrame() returns { document: null } before the iframe context is initialized, and CopyHostStyles doesn't guard against this.

Environment

  • Puck version: 0.21.1
  • Browser version: Chrome (desktop)
  • Additional environment info: Next.js 16.1.1 (Turbopack), React 19, Bun runtime, cacheComponents enabled in next.config

Steps to reproduce

  1. Create a Next.js 16 app with React 19
  2. Add Puck editor with server-side data fetching:
// page.tsx (Server Component)
import "@puckeditor/core/puck.css";
import { CatalogueEditor } from "./catalogue-editor";

export default function Page({ params }) {
  return (
    <Suspense fallback={<Loading />}>
      <EditorContent params={params} />
    </Suspense>
  );
}

async function EditorContent({ params }) {
  const data = await fetchData(params.id);
  return <CatalogueEditor data={data} />;
}
// catalogue-editor.tsx (Client Component)
"use client";
import { Puck } from "@puckeditor/core";

export function CatalogueEditor({ data }) {
  return <Puck config={config} data={data} />;
}
  1. Navigate to the editor page multiple times or refresh rapidly

What happens

Intermittent crash with error:

TypeError: Cannot read properties of null (reading 'document')
    at CopyHostStyles.useEffect (chunk-EBISZQTK.mjs:5632:39)
    at reconnectPassiveEffects (react-dom-client.development.js:17124:11)

The useFrame() hook returns { document: null, window: null } during React 19's hydration reconnection phase because autoFrameContext hasn't initialized the iframe yet. The getStyleSheet() function (line ~11240) then calls Array.from(document.styleSheets) without null checking.

What I expect to happen

The editor should render without errors. CopyHostStyles should guard against null document:

const { document: doc, window: win } = useFrame();

useEffect(() => {
  if (!doc || !win) return;  // Add this guard
  // ... rest of effect
}, [doc, win, ...]);

Additional Media

Workaround: Disabling iframe mode bypasses the issue:

<Puck config={config} data={data} iframe={{ enabled: false }} />

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions