facebook/react · error · Error

Expected overrideSuspenseMilestone() to not get called for…

Error message

Expected overrideSuspenseMilestone() to not get called for earlier React versions.

What it means

overrideSuspenseMilestone(suspendedSet) is the bulk variant used to force a whole set of Suspense boundaries to a milestone state (suspend all listed, resume the rest). Like the single-boundary override it requires setSuspenseHandler and scheduleUpdate from the renderer; on React versions that predate those DevTools hooks it throws, because there is no API to install the bulk handler.

Solutions

  1. Upgrade the page's React to a version that injects setSuspenseHandler and scheduleUpdate.
  2. Before sending the milestone action, verify supportsTogglingSuspense/canToggleSuspense for the renderer and every id in the set.
  3. Reload the page to re-run capability detection after renderer changes.
  4. If you maintain a custom frontend, disable milestone controls when the capability check fails instead of sending the message.
Defensive patterns

Strategy: validation

Validate before calling

// before a bulk/milestone suspend, verify the renderer capability once
const renderer = hook.renderers.get(rendererID);
const canMilestone =
  typeof renderer?.setSuspenseHandler === 'function' &&
  typeof renderer?.scheduleUpdate === 'function';
if (canMilestone) {
  bridge.send('overrideSuspenseMilestone', {ids, rendererID});
}

Prevention

When it happens

Trigger: A bulk suspend/unsuspend action (milestone navigation in the profiler/components UI, or a custom frontend sending the corresponding bridge message with an ID array) while the attached renderer is older than the version that introduced setSuspenseHandler/scheduleUpdate.

Common situations: Newer DevTools frontend driving an older pinned React renderer; embedding devtools-shared and wiring milestone controls without capability checks; renderers swapped by HMR.

Related errors


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

Appendix: source

Thrown at packages/react-devtools-shared/src/backend/fiber/renderer.js:7567

    if (!forceFallback && typeof scheduleRetry === 'function') {
      // If we're unsuspending and the renderer supports it, use a Retry instead of Sync
      // to allow for things like View Transitions to proceed the way they would for real.
      scheduleRetry(fiber);
    } else {
      scheduleUpdate(fiber);
    }
  }

  /**
   * Resets the all other roots of this renderer.
   * @param suspendedSet List of IDs of SuspenseComponent Fibers
   */
  function overrideSuspenseMilestone(suspendedSet: Array<FiberInstance['id']>) {
    if (
      typeof setSuspenseHandler !== 'function' ||
      typeof scheduleUpdate !== 'function'
    ) {
      throw new Error(
        'Expected overrideSuspenseMilestone() to not get called for earlier React versions.',
      );
    }

    const unsuspendedSet: Set<Fiber> = new Set(forceFallbackForFibers);

    let resuspended = false;
    for (let i = 0; i < suspendedSet.length; ++i) {
      const instance = idToDevToolsInstanceMap.get(suspendedSet[i]);
      if (instance === undefined) {
        console.warn(
          `Could not suspend ID '${suspendedSet[i]}' since the instance can't be found.`,
        );
        continue;
      }

      if (instance.kind === FIBER_INSTANCE) {
        const fiber = instance.data;

View on GitHub (pinned to eafeac097b)