facebook/react · error · Error
61
61
Error message
`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. Please visit https://react.dev/link/dangerously-set-inner-html for more information. What it means
dangerouslySetInnerHTML must be an object of the exact shape {__html: string}. During prop application on standard host elements (setProp), React checks `typeof value !== 'object' || !('__html' in value)` and throws when the shape is wrong. This guards the only sanctioned raw-HTML injection API, whose misuse is a classic XSS vector.
Source
Thrown at packages/react-dom-bindings/src/client/ReactDOMComponent.js:653
return;
}
case 'onScrollEnd': {
if (value != null) {
if (__DEV__ && typeof value !== 'function') {
warnForInvalidEventListener(key, value);
}
listenToNonDelegatedEvent('scrollend', domElement);
if (enableScrollEndPolyfill) {
// For use by the polyfill.
listenToNonDelegatedEvent('scroll', domElement);
}
}
return;
}
case 'dangerouslySetInnerHTML': {
if (value != null) {
if (typeof value !== 'object' || !('__html' in value)) {
throw new Error(
'`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
'Please visit https://react.dev/link/dangerously-set-inner-html ' +
'for more information.',
);
}
const nextHtml: any = value.__html;
if (nextHtml != null) {
if (props.children != null) {
throw new Error(
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
);
}
const lastHtml: any =
prevValue != null ? (prevValue as any).__html : undefined;
if (lastHtml !== nextHtml) {
domElement.innerHTML = nextHtml;
}
}View on GitHub (pinned to eafeac097b)
Solutions
- Use the exact shape: dangerouslySetInnerHTML={{__html: htmlString}}
- Sanitize the string with DOMPurify before injecting: dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(html)}}
- If the data arrives as a string field, wrap it at the call site instead of renaming keys downstream
- Prefer real JSX children or a markdown component when possible
Example fix
// before
<div dangerouslySetInnerHTML="<b>bold</b>"></div>
<div dangerouslySetInnerHTML={{html: '<b>bold</b>'}}></div>
// after
<div dangerouslySetInnerHTML={{__html: '<b>bold</b>'}}></div> Defensive patterns
Strategy: type-guard
Validate before calling
function toDangerousHtml(value: unknown): {__html: string} | undefined {
if (value == null) return undefined;
if (typeof value === 'object' && '__html' in value) return value as {__html: string};
if (typeof value === 'string') return {__html: DOMPurify.sanitize(value)};
throw new TypeError('dangerouslySetInnerHTML must be {__html: string} or a string to wrap');
} Type guard
const hasHtmlShape = (v: unknown): v is {__html: string} =>
typeof v === 'object' && v !== null && '__html' in v; Try / catch
Catch at the data edge, not in render: normalize any html field with toDangerousHtml() in a useMemo before passing props.
Prevention
- Centralize every dangerouslySetInnerHTML usage behind one sanitized helper
- DOMPurify.sanitize everything before it reaches __html
- Add a unit test asserting the helper always returns {__html: string}
When it happens
Trigger: Writing dangerouslySetInnerHTML="<b>hi</b>" (string), {{html: ...}} (missing double underscores), {{__html: ..., other: 1}} is fine shape-wise but typos like {{_html:}} or {{innerHTML:}} throw; also spreading props where dangerouslySetInnerHTML came from JSON data.
Common situations: Converting innerHTML assignments to React; copy-pasting docs with mangled underscores; data-driven rendering where the field is sometimes a plain string; markdown renderers misconfigured.
Related errors
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/f94b80f481f818d0.
Report an issue: GitHub.