facebook/react · error · Error

render: Unsupported Legacy Mode API.

Error message

render: Unsupported Legacy Mode API.

What it means

ReactFabric.render throws immediately when the renderer build was compiled with disableLegacyMode (the legacy root mode removed) and render is invoked without concurrentRoot=true. It is a hard guard that prevents the legacy ReactDOM.render-style entry point from silently creating an unsupported legacy root in builds where legacy mode no longer exists.

Source

Thrown at packages/react-native-renderer/src/ReactFabric.js:116

  if (logError === false) {
    return;
  }

  defaultOnCaughtError(error, errorInfo);
}
function nativeOnDefaultTransitionIndicator(): void | (() => void) {
  // Native doesn't have a default indicator.
}

function render(
  element: Element<ElementType>,
  containerTag: number,
  callback: ?() => void,
  concurrentRoot: ?boolean,
  options: ?RenderRootOptions,
): ?ElementRef<ElementType> {
  if (disableLegacyMode && !concurrentRoot) {
    throw new Error('render: Unsupported Legacy Mode API.');
  }

  let root = roots.get(containerTag);

  if (!root) {
    // TODO: these defaults are for backwards compatibility.
    // Once RN implements these options internally,
    // we can remove the defaults and ReactFiberErrorDialog.
    let onUncaughtError = nativeOnUncaughtError;
    let onCaughtError = nativeOnCaughtError;
    let onRecoverableError = defaultOnRecoverableError;

    if (options && options.onUncaughtError !== undefined) {
      onUncaughtError = options.onUncaughtError;
    }
    if (options && options.onCaughtError !== undefined) {
      onCaughtError = options.onCaughtError;
    }

View on GitHub (pinned to eafeac097b)

Solutions

  1. Switch to the concurrent API: ReactFabric.createRoot(containerTag, options).render(element), or RN's modern AppRegistry registration so concurrentRoot is true.
  2. Pass concurrentRoot=true at every call site you control.
  3. If legacy mode is genuinely required, run a react-native-renderer build matching your RN version where disableLegacyMode is off.

Example fix

// before
ReactFabric.render(<App />, containerTag, callback, false);

// after
const root = ReactFabric.createRoot(containerTag, {
  onUncaughtError,
  onCaughtError,
  onRecoverableError,
});
root.render(<App />);
Defensive patterns

Strategy: fallback

Try / catch

try {
  ReactFabric.render(element, containerTag, callback, false);
} catch (e) {
  if (/Unsupported Legacy Mode API/.test(e.message)) {
    ReactFabric.createRoot(containerTag).render(element);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling ReactFabric.render(element, containerTag, callback, concurrentRoot=null/falsy, options) on a renderer built with disableLegacyMode - typically the legacy AppRegistry/RN bridge render path, direct use of the internal render export, or test helpers still on the legacy API.

Common situations: Newer react-native-renderer builds where the flag is on; old RN apps or libraries pinned to the legacy render API; test setups that call ReactFabric.render directly with no concurrentRoot argument.

Related errors


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