Hydration Proof

Search documentation

Find a page or section

Minified React error #423

React rendered the whole page again in the browser.

Minified React error #423 means hydration failed outside any Suspense boundary, so React discarded the server HTML for the whole page and rendered it again in the browser. It is not the root cause. In React 18 it follows a mismatch (#418 or #425); in React 19, an error thrown during hydration. Fix the error logged before it.

The error

React 18:

Minified React error #423; visit https://reactjs.org/docs/error-decoder.html?invariant=423 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.

React 19:

Minified React error #423; visit https://react.dev/errors/423 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.

The full messages behind the code:

VersionFull message
React 18There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
React 19There was an error while hydrating but React was able to recover by instead client rendering the entire root.

What it means

React error 423 is a recovery message. Hydration failed somewhere that no <Suspense> boundary contains, so React had nothing smaller to fall back to: it rendered the entire root again, as if the page had no server HTML. The page works, but it renders twice, the content can flash, and anything typed before hydration is lost.

What came before it depends on the version:

  • React 18 logs #423 after every mismatch outside a boundary, right after #418 (an element differs) or #425 (text differs).
  • React 19 logs a mismatch as #418 alone. It logs #423 when a component threw an exception during hydration; the exception is attached as the error's cause.

Inside a boundary, the same failure is #422 and costs only that boundary. See there was an error while hydrating for both.

Minified React error #423 (Next.js)

In the Next.js App Router, React hydrates the whole document, so a mismatch in the root layout, or in a page with no loading.tsx or other <Suspense> above it, renders everything again. A loading.tsx file wraps its segment in a Suspense boundary, so a failure inside it renders only that segment again, and React logs #422 instead of #423. In the Pages Router the root is the #__next element.

Next.js production builds do not show an overlay, so the code only appears in the browser console and in your error tracking.

How to fix it

  1. Find the error logged before #423 and decode it: usually #418. Its page tells you how to find the element.

  2. Fix that error. When #423 is the only error, in React 19, expand its cause or reproduce the page in development to see the exception.

  3. Add Suspense boundaries so the next failure costs one part of the page. In the Next.js App Router, a loading.tsx does it for a route segment:

    app/dashboard/loading.tsx
    export default function Loading() {
      return <p>Loading dashboard…</p>;
    }

Find every instance

hydration-proof reports the whole-root fallback as HP2004 and the discarded page as HP1011, and the mismatch that started it as its own finding, with the element and the source line:

npx hydration-proof test --mode both

The ESLint rules catch the usual sources of that first mismatch, such as the clock, window and locale formatting, in the editor.