facebook/react · error · Error

509

509

Error message

ReactDOM: Unsupported Legacy Mode API.

What it means

ReactDOM.render is the legacy root API. With the disableLegacyMode flag (React 19 builds) it logs a migration note in DEV and then throws 'ReactDOM: Unsupported Legacy Mode API.' (code 509), making removal a hard error. The replacement is createRoot(container).render(element); the old callback second argument becomes an effect. Note this throw fires before the container validity check, so a bad container never reaches the code-299 error in this build.

Source

Thrown at packages/react-dom/src/client/ReactDOMRootFB.js:399

  }
  if (__DEV__) {
    return findHostInstanceWithWarning(componentOrElement, 'findDOMNode');
  }
  return findHostInstance(componentOrElement);
}

export function render(
  element: React$Element<any>,
  container: Container,
  callback: ?Function,
): component(...props: any) | PublicInstance | null {
  if (disableLegacyMode) {
    if (__DEV__) {
      console.error(
        'ReactDOM.render was removed in React 19. Use createRoot instead.',
      );
    }
    throw new Error('ReactDOM: Unsupported Legacy Mode API.');
  }
  if (__DEV__) {
    console.error(
      'ReactDOM.render has not been supported since React 18. Use createRoot ' +
        'instead. Until you switch to the new API, your app will behave as ' +
        "if it's running React 17. Learn " +
        'more: https://react.dev/link/switch-to-createroot',
    );
  }

  if (!isValidContainer(container)) {
    throw new Error('Target container is not a DOM element.');
  }

  if (__DEV__) {
    const isModernRoot =
      isContainerMarkedAsRoot(container) &&
      container._reactRootContainer === undefined;

View on GitHub (pinned to eafeac097b)

Solutions

  1. Replace ReactDOM.render(el, container, cb) with createRoot(container).render(<App />) and move the callback into a useEffect
  2. Replace ReactDOM.hydrate with hydrateRoot(container, initialChildren)
  3. Run the React 19 upgrade codemod and search the repo for ReactDOM.render leftovers
  4. Update or replace dependencies that internally call ReactDOM.render

Example fix

// before
import ReactDOM from 'react-dom';
ReactDOM.render(<App />, document.getElementById('root'));

// after
import {createRoot} from 'react-dom/client';
createRoot(document.getElementById('root')).render(<App />);
Defensive patterns

Strategy: fallback

Validate before calling

import * as ReactDOM from 'react-dom';
import {version} from 'react';

const isLegacyRemoved = Number(version.split('.')[0]) >= 19;

function mountApp(element, container) {
  if (isLegacyRemoved) {
    // React 19+: modern API
    import('react-dom/client').then(({createRoot}) => {
      createRoot(container).render(element);
    });
  } else {
    ReactDOM.render(element, container);
  }
}

Prevention

When it happens

Trigger: Calling ReactDOM.render(<App />, container, callback?) (or ReactDOM.hydrate) on a build where disableLegacyMode is true — i.e. React 19 — including via old tutorials, legacy wrappers, or dependencies that still call it.

Common situations: Upgrading React 17/18 codebases to 19 without migrating entry points; libraries wrapping ReactDOM.render (legacy modal or widget managers); call sites missed by upgrade codemods.

Related errors


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