Hydration Proof

Search documentation

Find a page or section

HP2004: The root switched to client rendering

HP2004 (root client rendered): an error during hydration outside any Suspense boundary made React render the whole page on the client (React error #423).

HP2004 (root-client-rendered) means an error during hydration happened outside every Suspense boundary, so React gave up on the whole root and rendered the entire page on the client. In production this is minified React error #423. Fix the error React reported, and wrap unstable parts in Suspense boundaries so one failure cannot re-render the whole page.

CodeHP2004
Nameroot-client-rendered
Default severityError
GroupProblems React reported
What it meansAn error during hydration outside any Suspense boundary made React render the whole root on the client.

What HP2004 (root-client-rendered) means

React recovers from a hydration failure at the nearest Suspense boundary above it. With none in between, that is the root: the server HTML of the whole page is discarded, every component renders again in the browser, and anything the user did before hydration is lost.

hydration-proof normally sees the discarded root in the DOM as well, and reports the concrete difference with React's message as evidence, or HP1011 when it cannot locate one. HP2004 is React's report when no DOM finding from that commit explains it.

The React error it matches

There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

This is React 18's message; production builds show minified React error #423. See there was an error while hydrating. When the failure is inside a boundary, only that boundary switches: HP2003.

Likely causes

A mismatch in a part of the page with no Suspense boundary above it, often in a layout every page shares: a theme class, a time value, browser storage or invalid HTML.

How to fix it

  • Wrap unstable parts in Suspense boundaries so a hydration error does not re-render the whole page.

Fix the error itself first: the finding's evidence has React's message and the component stack, and npx hydration-proof test --mode dev gives readable names and source lines. A boundary then keeps the next failure local:

app/layout.tsx
import { Suspense, type ReactNode } from "react";
 
import { AccountMenu } from "./account-menu";
 
export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <header>
          <Suspense fallback={null}>
            <AccountMenu />
          </Suspense>
        </header>
        {children}
      </body>
    </html>
  );
}

If AccountMenu fails to hydrate, React now client-renders that boundary only, and the finding becomes HP2003 instead.

Example

  ✖ / 1.2s  1 error
    HP2004 The root switched to client rendering
      There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
      → Wrap unstable parts in Suspense boundaries so a hydration error does not re-render the whole page.