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

  1. Use the exact shape: dangerouslySetInnerHTML={{__html: htmlString}}
  2. Sanitize the string with DOMPurify before injecting: dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(html)}}
  3. If the data arrives as a string field, wrap it at the call site instead of renaming keys downstream
  4. 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

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.