"There was an error while hydrating" is a follow-up, not the bug itself: React logs it after another error during hydration, to say it discarded the server HTML and rendered that part in the browser instead. Error #423 means the whole page; #422 means one Suspense boundary. Fix the error logged before it.
The error
React 18, when the failure is outside any <Suspense> boundary (#423):
Uncaught Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.React 18, inside a boundary (#422):
Uncaught Error: There was an error while hydrating this Suspense boundary. Switched to client rendering.React 18 also logs this warning in development when the whole root falls
back. The tag is your root container: <div> for a #root or #__next
element, <#document> when React hydrates the whole document:
Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.React 19 reworded both:
There was an error while hydrating but React was able to recover by instead client rendering the entire root.
There was an error while hydrating but React was able to recover by instead client rendering from the nearest Suspense boundary.Production builds print Minified React error #423 or #422. See
minified React error #423.
What there was an error while hydrating means
Hydration failed somewhere, and React recovered by rendering part of the page from scratch in the browser. Which part depends on where the failure was:
| Where it failed | React 18 | React 19 | What React renders again |
|---|---|---|---|
Outside any <Suspense> | #423 | #423 | The whole root: the entire page |
Inside a <Suspense> boundary | #422 | #422 | Only that boundary |
The page keeps working, which is why this is a recoverable error. But the server's work is thrown away, the content may flash, and anything a user typed before hydration is lost.
The cause differs by version:
- React 18 logs it after every hydration mismatch, following "Hydration failed because the initial UI does not match" (#418) or "Text content does not match server-rendered HTML" (#425). Fix that first error.
- React 19 logs a mismatch as #418 only. It logs #422 or #423 when a
component threw an exception while hydrating. The original exception is the
error's
cause: expand it in the console.
Common causes
- A hydration mismatch (React 18): a time, a locale-formatted value, a
typeof windowbranch, invalid nesting. See common causes of hydration errors. - A component that throws only in the browser: it reads a property of data that the browser does not have yet, or calls an API that fails there. See server and client data.
useSyncExternalStorewithout a server snapshot, which throws "Missing getServerSnapshot".
A boundary that React 18 rendered again because it received an update too early has its own message: Suspense boundary received an update before hydrating (#421).
How to fix it
-
Scroll up to the first error. In React 18, it is the warning and the error logged just before this one. In React 19, expand
cause. -
Fix that error using its page in the list of hydration error messages.
-
Add
<Suspense>boundaries around independent parts of the page. A failure then costs one boundary (#422) instead of the whole root (#423):app/dashboard/page.tsx import { Suspense } from "react"; import { ActivityFeed } from "./activity-feed"; import { Stats } from "./stats"; export default function Dashboard() { return ( <main> <Stats /> <Suspense fallback={<p>Loading activity…</p>}> <ActivityFeed /> </Suspense> </main> ); }A boundary limits the damage. It does not fix the mismatch inside it.
Find every instance
hydration-proof reports a boundary React rendered again as HP2003 and a root as HP2004, with React's error attached, and the mismatch that started it (for example HP1001) as its own finding with the source line:
npx hydration-proof test --mode bothA page rendered again from scratch is also reported as HP1011, and a single branch as HP1010. The ESLint rules catch most of the mismatches that start the chain.