HP1006 (missing-attribute) means React renders an attribute on the client
that the server HTML does not have. React does not add it during hydration, so
the element goes without it until it re-renders: a link without its target,
a control without its aria-* state. Render the attribute on the server as
well, or add it after mount.
| Code | HP1006 |
|---|---|
| Name | missing-attribute |
| Default severity | Error |
| Group | DOM mismatches |
| What it means | React renders an attribute on the client that the server HTML does not have. |
What HP1006 (missing-attribute) means
The element exists on both sides, but one attribute is only in React's client
props. The component computed it from something only the browser has, so the
server rendered undefined and left it out.
React does not patch attributes during hydration, and React 19 production
builds report nothing. hydration-proof compares every reused element's
attributes with the props React renders for it, so it finds the missing
attribute in production too. A missing class or style is reported as
HP1004 or HP1003.
The React error it matches
In development, React 19 prints:
A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up.Likely causes
- A value from a browser-only API, such as touch
support or
navigator.language, that isundefinedon the server. - A flag read from browser storage or a media query.
- A random value or generated id created only in the browser.
How to fix it
- Render the attribute on the server as well, or add it after mount in
useEffect.
"use client";
export function ShareButton() {
const touch = typeof window !== "undefined" && "ontouchstart" in window;
return (
<button type="button" data-input={touch ? "touch" : undefined}>
Share
</button>
);
}Start from the value the server can render, and switch after hydration:
"use client";
import { useEffect, useState } from "react";
export function ShareButton() {
const [touch, setTouch] = useState(false);
useEffect(() => {
setTouch("ontouchstart" in window);
}, []);
return (
<button type="button" data-input={touch ? "touch" : undefined}>
Share
</button>
);
}Prevent it with ESLint
no-browser-global-in-render and
no-window-render-branch report the
browser reads and branches that cause it.
When the difference is intentional
suppressHydrationWarning on the element keeps the server's attributes without
a warning; hydration-proof then lists the difference as
HP6001 (info). ignore.attributes stops comparing an
attribute everywhere. See ignoring findings.
Example
✖ /posts/42 1.1s 1 error
HP1006 Attribute missing from the server HTML (browser-only api used during render, 60%)
article > button in ShareButton
attribute: data-input
server: (absent)
client: "touch"
components/share-button.tsx:7:5
→ 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.