Every finding carries one of the hydration-proof issue codes: HP1001 for text
that differs between server and client, HP3001 for invalid HTML nesting, and
so on. A code never changes meaning, so you can use it in ignore rules,
baselines and budgets. Each code below links to a page with its causes and
fixes.
How to read a code
The first digit is the group. Each code also has a kebab-case name
(text-mismatch) that is as stable as the code itself.
| Codes | Group | What went wrong |
|---|---|---|
| HP1xxx | DOM mismatches | The server HTML and the first client render differ |
| HP2xxx | Problems React reported | React logged an error or warning no DOM finding explains, or a script threw |
| HP3xxx | Markup the browser repaired | The HTML parser rewrote invalid markup, or ids collide |
| HP4xxx | Changes made outside React | A script, extension, CDN or proxy changed the page |
| HP5xxx | Interaction during hydration | Input, clicks, focus, scroll or navigation broke while the page hydrated |
| HP6xxx | suppressHydrationWarning audit | What suppressHydrationWarning hides, or fails to hide |
| HP9xxx | Test run problems | The page could not be tested properly |
The code shows up everywhere a finding does: the terminal, report.json, the
HTML report, the SARIF rule id, the JUnit failure type and the GitLab
check_name. See report formats for each one.
Severity and --fail-on
Every code has a default severity. It decides whether the run fails:
| Severity | Terminal | Fails the run |
|---|---|---|
error | Listed, the page is marked failed | By default |
warning | Listed, the page is marked with a warning | With --fail-on warning or --fail-on info |
info | Not listed; in the JSON and HTML reports | Only with --fail-on info |
--fail-on never (or ci.failOn: 'never') never fails the run, and
ci.maxWarnings fails it when there are more warnings than you allow. A
finding's severity is usually its code's default; a few are raised or lowered.
For example, a difference hidden by suppressHydrationWarning that does not
look intentional is a warning instead of info. Budgets per severity, route or
code are covered in baselines and budgets.
Ignore a code
Ignored findings stay in the report, marked as ignored, and do not fail the run. A rule needs a reason, and an expiry date keeps a temporary exception from becoming permanent: once it passes, the finding fails the run again.
import { defineConfig } from "hydration-proof";
export default defineConfig({
ignore: {
issues: [
{
code: "HP1004",
route: "/legacy/**",
reason: "Old theme system",
expires: "2026-12-31",
},
],
},
});A rule can match a code, a route glob, a selector or a fingerprint.
Ignoring findings covers selectors, attributes and text
patterns as well.
Fingerprints
Every finding also has a fingerprint. It stays the same across runs as long as the problem is the same: same code, route pattern, element and attribute. Ignore rules and baselines match on it, and the SARIF report passes it to code scanning, so an alert is recognized from one run to the next.
DOM mismatches
The server HTML and the first client render differ: text, attributes, inline styles, class names, elements, whitespace, form state or the document head. It also covers the branches React threw away and rendered again on the client.
| Code | Title | Severity |
|---|---|---|
| HP1001 | Text differs between server and client | Error |
| HP1002 | Attribute differs between server and client | Error |
| HP1003 | Inline style differs between server and client | Error |
| HP1004 | Class name differs between server and client | Error |
| HP1005 | Attribute only present in the server HTML | Warning |
| HP1006 | Attribute missing from the server HTML | Error |
| HP1007 | Different element rendered on server and client | Error |
| HP1008 | Element only present in the server HTML | Error |
| HP1009 | Element missing from the server HTML | Error |
| HP1010 | React discarded server HTML and rendered a branch again | Error |
| HP1011 | React discarded the whole server-rendered page | Error |
| HP1012 | Form state differs between server and client | Warning |
| HP1013 | dangerouslySetInnerHTML differs between server and client | Error |
| HP1014 | Document head differs between server and client | Warning |
| HP1015 | Whitespace differs between server and client | Error |
Problems React reported
Errors and warnings React logged itself. When a DOM finding explains them, React's message is attached to that finding as evidence instead; these codes are for the reports nothing else explains, and for page errors.
| Code | Title | Severity |
|---|---|---|
| HP2001 | React reported a hydration error | Error |
| HP2002 | React warned about a hydration mismatch | Warning |
| HP2003 | A Suspense boundary switched to client rendering | Error |
| HP2004 | The root switched to client rendering | Error |
| HP2005 | An update arrived before hydration finished | Warning |
| HP2006 | The server could not finish rendering a boundary | Error |
| HP2007 | Uncaught error while loading the page | Warning |
Markup the browser repaired
Nesting the HTML parser rewrites before React hydrates, nested interactive
elements, duplicate ids and useId collisions between React roots.
| Code | Title | Severity |
|---|---|---|
| HP3001 | Invalid HTML nesting | Error |
| HP3002 | Interactive element nested in another | Error |
| HP3003 | Duplicate id attribute | Info |
| HP3004 | Two React roots generate the same ids | Warning |
Changes made outside React
Scripts, browser extensions, CDNs and proxies that changed the page before React hydrated it.
| Code | Title | Severity |
|---|---|---|
| HP4001 | The page was modified before React hydrated | Error |
| HP4002 | A browser extension changed the page | Info |
| HP4003 | HTML was rewritten between the server and the browser | Error |
Interaction during hydration
What a user does before the page is interactive, and client-side navigation
compared with a direct load. Most of these need checks.interactions or
checks.navigation.
| Code | Title | Severity |
|---|---|---|
| HP5001 | An interaction before hydration was lost | Warning |
| HP5002 | User input was reset during hydration | Error |
| HP5003 | Focus was lost during hydration | Warning |
| HP5004 | The page differs after client-side navigation | Warning |
| HP5005 | Client-side navigation failed | Error |
| HP5006 | An element handles the same event twice | Warning |
| HP5007 | Scroll position was reset during hydration | Warning |
| HP5008 | A custom interaction failed | Error |
suppressHydrationWarning audit
Differences that suppressHydrationWarning hides, structural differences it
cannot hide, and suppressions with nothing to suppress.
| Code | Title | Severity |
|---|---|---|
| HP6001 | Mismatch hidden by suppressHydrationWarning | Info |
| HP6002 | suppressHydrationWarning cannot hide a structural difference | Error |
| HP6003 | suppressHydrationWarning with nothing to suppress | Info |
Test run problems
The page did not load, React never hydrated, or the page never settled.
| Code | Title | Severity |
|---|---|---|
| HP9001 | Hydration did not finish in time | Error |
| HP9002 | No React found on the page | Warning |
| HP9003 | The page is rendered on the client only | Info |
| HP9004 | The page could not be loaded | Error |
| HP9005 | The server answered with an error status | Error |
| HP9006 | The server HTML could not be captured | Warning |
| HP9007 | Some capture data was dropped | Warning |
| HP9008 | React loaded but never mounted a root | Warning |
| HP9009 | The page never became quiet | Warning |
| HP9010 | The route redirected somewhere else | Warning |
Related
- Common causes of hydration errors, with a fix for each
- React hydration error messages, decoded
- Ignoring findings on purpose
- How hydration-proof works: which comparison finds what
- Detect hydration errors in CI