facebook/react · error · Error

299

299

Error message

Target container is not a DOM element.

What it means

The top-level react-dom entry re-exports createPortal with the same isValidContainer validation as the client build (nodeType ELEMENT, DOCUMENT, or DOCUMENT_FRAGMENT), throwing error 299 for null or non-DOM containers. A distinct trap for this entry point: importing createPortal from 'react-dom' in non-DOM environments like React Native fails here because no real DOM nodes exist at all.

Source

Thrown at packages/react-dom/src/shared/ReactDOM.js:63

    console.error(
      'React depends on Map and Set built-in types. Make sure that you load a ' +
        'polyfill in older browsers. https://reactjs.org/link/react-polyfills',
    );
  }
}

function batchedUpdates<A, R>(fn: (a: A) => R, a: A): R {
  // batchedUpdates is now just a passthrough noop
  return fn(a);
}

function createPortal(
  children: ReactNodeList,
  container: Element | DocumentFragment,
  key: ?string = null,
): React$Portal {
  if (!isValidContainer(container)) {
    throw new Error('Target container is not a DOM element.');
  }

  // TODO: pass ReactDOM portal implementation as third argument
  // $FlowFixMe[incompatible-type] The Flow type is opaque but there's no way to actually create it.
  return createPortalImpl(children, container, null, key);
}

export {
  ReactVersion as version,
  browser,
  createPortal,
  flushSync,
  batchedUpdates as unstable_batchedUpdates,
  prefetchDNS,
  preconnect,
  preload,
  preloadModule,
  preinit,

View on GitHub (pinned to eafeac097b)

Solutions

  1. Null-check the container before creating the portal
  2. Prefer the createPortal re-export from 'react-dom/client' for web apps
  3. On React Native, use a modal/portal library built for native instead of react-dom's createPortal
  4. Ensure the host element is present before the render that creates the portal

Example fix

// before
import {createPortal} from 'react-dom';
createPortal(<Menu />, document.getElementById('menu-host'));

// after
import {createPortal} from 'react-dom/client';
const host = document.getElementById('menu-host');
if (host) {
  createPortal(<Menu />, host);
}
Defensive patterns

Strategy: type-guard

Validate before calling

const isValidPortalContainer = (node: unknown): boolean =>
  !!(
    node &&
    typeof node === 'object' &&
    (node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11)
  );

const host = document.getElementById('menu-host');
if (isValidPortalContainer(host)) {
  createPortal(<Menu />, host);
}

Type guard

function isValidPortalContainer(node: unknown): node is Element | Document | DocumentFragment {
  return !!(
    node &&
    typeof node === 'object' &&
    (node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11)
  );
}

Prevention

When it happens

Trigger: import {createPortal} from 'react-dom' with a container that is null (failed getElementById), a selector string, a wrapped node, or — in React Native — any host component, since those are not DOM elements.

Common situations: Shared code that renders portals imported by both web and React Native builds; missing portal host divs in templates; containers looked up before they exist.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/0df95418b076074b. Report an issue: GitHub.