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:
| Version | Full message |
|---|---|
| React 18 | There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering. |
| React 19 | There 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
-
Find the error logged before #423 and decode it: usually #418. Its page tells you how to find the element.
-
Fix that error. When #423 is the only error, in React 19, expand its
causeor reproduce the page in development to see the exception. -
Add Suspense boundaries so the next failure costs one part of the page. In the Next.js App Router, a
loading.tsxdoes 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 bothThe ESLint rules catch the usual sources of that first
mismatch, such as the clock, window and locale formatting, in the editor.