The Exact Error
Error: Hydration failed because the server rendered HTML didn't match the client.
Or, in slightly different phrasing depending on the React version:
Hydration failed because the initial UI does not match what was rendered on the server.
Text content does not match server-rendered HTML.
Warning: Text content did not match. Server: "..." Client: "..."
There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
Quick summary: React rendered your component tree once on the server and sent HTML to the browser, then rendered it again on the client to attach event listeners ("hydration"). The two renders produced different output. React detects the mismatch, logs a warning (and in newer versions, the exact mismatched text or attribute), and re-renders the affected subtree on the client to recover.
Why This Error Happens
Hydration assumes the server render and the first client render produce identical output. Anything that can differ between those two environments breaks that assumption. Six causes account for almost every real-world case:
1. Browser-only APIs read during render ā window, document, localStorage, or navigator don't exist on the server. Reading them directly in a component body (not inside useEffect) either throws server-side or silently returns a different value than the client gets.
2. Date and time formatting ā new Date().toLocaleString() or toLocaleDateString() without an explicit locale and time zone renders using the server's time zone (usually UTC) and the client's time zone (the visitor's local time) ā two different strings for the same instant.
3. Math.random() or crypto.randomUUID() during render ā generates a new value on the server and a different one on the client, every single time.
4. Browser extensions modifying the DOM ā Grammarly, password managers, and some ad blockers inject attributes or wrapper elements into the page before React hydrates. React sees DOM that doesn't match what it rendered server-side, even though your component code is correct.
5. Invalid HTML nesting ā a <div> inside a <p>, or a <tr> not inside a <table>/<tbody>, gets silently corrected by the browser's HTML parser into a different DOM structure than React actually rendered, which hydration then detects as a mismatch.
6. typeof window !== "undefined" branches in render ā a common pattern for "only run this on the client," but if it's used directly in the render body rather than inside useEffect, the server (where window is undefined) and client (where it's defined) render two different trees on purpose.
Step-by-Step Diagnosis
Step 1 ā Read the diff React gives you
In development mode, React prints the actual mismatched text or attribute:
Warning: Text content did not match. Server: "11/4/2026" Client: "4/11/2026"
That's almost always enough to identify the cause directly ā here, a date formatted with two different locales.
Step 2 ā Rule out a browser extension
Open the page in an incognito/private window with extensions disabled. If the warning disappears, it's an extension injecting markup, not your code ā safe to ignore (or add suppressHydrationWarning to the specific element it's modifying, usually <body>).
Step 3 ā Search your component for render-time browser API access
function Clock() {
const now = new Date(); // ā different on server vs. client
return <span>{now.toLocaleTimeString()}</span>;
}
Any window, localStorage, Date.now(), or Math.random() called directly in the function body (not inside useEffect) is a candidate.