HP1001 (text-mismatch) means the text in the server HTML differs from the
text React rendered in the browser's first render. The finding gives both
values, the element and, in development builds, the line that rendered it.
Find what that component reads that differs between the two renders (the
clock, the locale, browser storage) and make it the same.
| Code | HP1001 |
|---|---|
| Name | text-mismatch |
| Default severity | Error |
| Group | DOM mismatches |
| What it means | The server HTML contains different text than the browser rendered during hydration. |
What HP1001 (text-mismatch) means
React expects the first client render to produce exactly the text the server sent. When a text node differs, React discards the server HTML up to the nearest Suspense boundary and renders that part again on the client, which is slower and resets state.
hydration-proof finds the difference in two ways:
- It compares the DOM right before and inside the hydration commit, which shows the text React replaced.
- It compares the server text of every element React reused with the text React renders for it, which also catches text React left in place.
When the text sits inside a branch React re-rendered, the finding says so in
its evidence ("React discarded the server HTML of <section> and rendered it
again on the client"), and no separate HP1010 is
reported. If only whitespace differs, the code is
HP1015 instead.
The React error it matches
In a development build, React usually reports the same problem, and hydration-proof attaches React's message to the finding as evidence. These are the messages for a text difference:
Hydration failed because the server rendered text didn't match the client.
Text content does not match server-rendered HTML.
Warning: Text content did not match. Server: "5:00 AM" Client: "10:00 AM"
Minified React error #418; visit https://react.dev/errors/418Text content does not match server-rendered HTML covers the React 18 wording, and the server rendered HTML didn't match the client the React 19 one.
Likely causes
Each finding names its most likely cause with a confidence score. These are the causes behind HP1001 in the package's own test pages:
| Cause | What differs |
|---|---|
| Time-dependent value | Date.now() or new Date() read during render |
| Timezone difference | A date formatted in the server's and the browser's timezone |
| Locale-dependent formatting | toLocaleString() with the runtime's default locale |
| Random value | Math.random() or crypto.randomUUID() in render |
| Browser storage | localStorage read behind a typeof window check |
| Media query | matchMedia or the window size read during render |
| Browser-only API | navigator.userAgent and other browser globals |
| Different data | The client fetched the data again and got a new result |
How to fix it
- Render exactly the same text on the server and in the first client render.
- Move browser-only or time-dependent values into
useEffect, or compute them on the server and pass them down as props.
For example, a greeting that reads localStorage renders "guest" on the server
and the stored name in the browser:
"use client";
export function Welcome() {
const name =
typeof window === "undefined"
? "guest"
: (localStorage.getItem("name") ?? "guest");
return <p>Welcome back, {name}</p>;
}Render the value both sides agree on first, and read storage after hydration:
"use client";
import { useEffect, useState } from "react";
export function Welcome() {
const [name, setName] = useState("guest");
useEffect(() => {
setName(localStorage.getItem("name") ?? "guest");
}, []);
return <p>Welcome back, {name}</p>;
}The cause page for your finding has the fix that fits it: pass the server's
time as a prop, pass an explicit locale and timeZone, or send the data the
server rendered with. hydration-proof test --probe reloads the page with one
factor changed at a time (clock, random seed, locale, timezone, theme,
viewport, storage) and turns the likely cause into a proven one; see
probes.
Prevent it with ESLint
The ESLint plugin reports the usual sources in render code:
no-date-in-render,
no-random-in-render,
no-locale-without-explicit-locale,
no-timezone-without-explicit-timezone,
no-storage-in-initial-render and
no-window-render-branch.
When the difference is intentional
For a value that is meant to differ, such as a live clock, put
suppressHydrationWarning on the element that holds it: React keeps the server
text, and hydration-proof lists the difference as
HP6001 (info) instead. ignore.textPatterns ignores a
text difference when both values are equal after removing the patterns, for
example /\d{2}:\d{2}/ for times. See ignoring findings.
Example
✖ /status 842ms 1 error
HP1001 Text differs between server and client (time-dependent value, 97%)
#rendered-at in RenderedAt
server: "Rendered at 1767225600000"
client: "Rendered at 1767225600412"
app/status/rendered-at.tsx:4:10
→ The server and the browser render at different moments. Pass the timestamp the server used as a prop, or render the time after mount (useEffect).The last line is the fix for the likely cause. The HTML report adds the code around that line, React's message and a screenshot with the element outlined.