HP1013 (inner-html-mismatch) means dangerouslySetInnerHTML produced
different markup on the server and in the browser. React keeps the server's
version during hydration; React 19 production builds may not warn you. Send
the same HTML to both sides, or render it after mount.
| Code | HP1013 |
|---|---|
| Name | inner-html-mismatch |
| Default severity | Error |
| Group | DOM mismatches |
| What it means | The HTML injected with dangerouslySetInnerHTML differs between the server and the client. React does not patch it. |
What HP1013 (inner-html-mismatch) means
The element exists on both sides, but the __html string React renders on the
client does not produce the same content as the server HTML. hydration-proof
parses the client's string in an inert document and compares the result with
the element's content, so markup that parses to the same thing (<br/> and
<br>, for example) is not reported.
The finding has no single server or client value; the HTML report shows both versions of the element side by side.
The React error it matches
React 18 warns about it in development:
Warning: Prop `dangerouslySetInnerHTML` did not match.See Prop className did not match,
which covers this variant of the warning too. React 19 production builds report
nothing.
Likely causes
- HTML built behind a
typeof windowcheck, or processed only in the browser (sanitized, highlighted, rewritten): a browser-only API. The package's/dangerous-htmltest page injects different markup on each side this way. - A string that contains a time or a number formatted with the runtime's locale.
- Content the client fetched again: different data.
How to fix it
- Make the injected HTML identical on server and client, or render it after mount.
Processing the HTML only in the browser gives the two renders different strings:
"use client";
import { highlight } from "./highlight";
export function PostBody({ html }: { html: string }) {
const content = typeof window === "undefined" ? html : highlight(html);
return <div id="post-body" dangerouslySetInnerHTML={{ __html: content }} />;
}Do the processing once, where the data is loaded (on the server or at build time), and pass the finished string to both renders:
export function PostBody({ html }: { html: string }) {
return <div id="post-body" dangerouslySetInnerHTML={{ __html: html }} />;
}Prevent it with ESLint
no-window-render-branch reports the
server/browser branch, and
no-date-in-render and
no-locale-without-explicit-locale
the values that change the string.
Example
✖ /blog/launch 1.0s 1 error
HP1013 dangerouslySetInnerHTML differs between server and client · components/post-body.tsx:7
The markup injected with dangerouslySetInnerHTML differs from what the client renders.
Possible cause: Browser-only api used during render. Fix: Code like `typeof window !== "undefined"` or window/navigator/document access renders differently on the server. Read browser values in useEffect, or render th…