HP1002 (attribute-mismatch) means an attribute such as href, id or
data-* has one value in the server HTML and another in the props React
renders on the client. React does not patch attributes during hydration, so
users keep the server value. Compute the attribute from data both sides share.
| Code | HP1002 |
|---|---|
| Name | attribute-mismatch |
| Default severity | Error |
| Group | DOM mismatches |
| What it means | An attribute value in the server HTML differs from the value React rendered on the client. React does not patch attributes during hydration. |
What HP1002 (attribute-mismatch) means
The element exists on both sides and React reuses it, but one attribute
differs. React keeps whatever the server sent until the element re-renders for
another reason: a link keeps pointing at the server's URL, an aria-* value
stays wrong, a datetime stays stale.
Attribute codes are split by what differs:
| Difference | Code |
|---|---|
| A value on both sides, but different | HP1002 |
style | HP1003 |
class | HP1004 |
| Only in the server HTML | HP1005 |
| Only in React's client render | HP1006 |
hydration-proof compares every attribute React reused with the props React
renders for that element, so it finds attribute mismatches in production
builds, where React 19 reports nothing. Boolean attributes such as disabled
and hidden are compared by presence. An attribute that changes during the
hydration commit, for example from a layout effect, is an update and not a
mismatch, so it is not reported.
The React error it matches
Only development builds report it:
A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up.
Warning: Prop `href` did not match. Server: "/pricing?region=eu-west" Client: "/pricing?region=us-east"The first is React 19, the second React 18. See
attributes didn't match
and Prop className did not match
for the React 18 warning, which names the prop that differs.
Likely causes
- A
typeof windowbranch or another browser-only API in the value, like the package's/attr-mismatchtest page, which builds anhreffrom a region that differs on each side. - The theme: an SVG
fillchosen withprefers-color-scheme, as on the/svg-attrtest page. - A generated id from a counter or a random value
in
id,fororaria-*attributes. - A time-dependent value in
datetimeortitle, or a random value anywhere.
How to fix it
- Compute the attribute from data that is identical on the server and the client.
- React does not fix attributes during hydration, so users keep seeing the server value until the next update.
Here the server and the browser pick a different region:
"use client";
export function PricingLink() {
const region = typeof window === "undefined" ? "eu-west" : "us-east";
return <a href={`/pricing?region=${region}`}>See pricing</a>;
}Decide the value once, on the server (from a cookie, a header or the route), and pass it down, so both renders use the same string:
export function PricingLink({ region }: { region: string }) {
return <a href={`/pricing?region=${region}`}>See pricing</a>;
}For ids, use useId instead of counters or random values.
Prevent it with ESLint
no-window-render-branch reports
server/browser branches in render code,
no-browser-global-in-render
browser globals, and no-unstable-id ids built
from random values, the clock or counters.
When the difference is intentional
suppressHydrationWarning covers an element's own attributes: React keeps the
server value, and hydration-proof lists it as HP6001
(info). To stop comparing an attribute everywhere (tracking attributes, for
example), list it in ignore.attributes. See
ignoring findings.
Example
✖ /pricing 1.2s 1 error
HP1002 Attribute differs between server and client (browser-only api used during render, 59%)
#pricing-link in PricingLink
attribute: href
server: "/pricing?region=eu-west"
client: "/pricing?region=us-east"
components/pricing-link.tsx:5:10
→ Code like `typeof window !== "undefined"` or window/navigator/document access renders differently on the server. Read browser values in useEffect, or render the component on the client only.