facebook/react · error · Error

435

435

Error message

Unexpected Suspense handler tag (${finishedWork.tag}). This is a bug in React.

What it means

attachSuspenseRetryListeners() subscribes to the thenables (wakeables) a boundary suspended on, so resolving them can retry the boundary. The retry cache lives on the boundary's state node, and getRetryCache() only knows how to fetch it for Suspense, SuspenseList, Activity, and Offscreen fibers. Any other tag reaching this code means a wakeable was queued on a fiber type that cannot own one.

Source

Thrown at packages/react-reconciler/src/ReactFiberCommitWork.js:1970

    case SuspenseComponent:
    case SuspenseListComponent: {
      let retryCache = finishedWork.stateNode;
      if (retryCache === null) {
        retryCache = finishedWork.stateNode = new PossiblyWeakSet();
      }
      return retryCache;
    }
    case OffscreenComponent: {
      const instance: OffscreenInstance = finishedWork.stateNode;
      let retryCache: null | Set<Wakeable> | WeakSet<Wakeable> =
        instance._retryCache;
      if (retryCache === null) {
        retryCache = instance._retryCache = new PossiblyWeakSet();
      }
      return retryCache;
    }
    default: {
      throw new Error(
        `Unexpected Suspense handler tag (${finishedWork.tag}). This is a ` +
          'bug in React.',
      );
    }
  }
}

function attachSuspenseRetryListeners(
  finishedWork: Fiber,
  wakeables: RetryQueue,
) {
  // If this boundary just timed out, then it will have a set of wakeables.
  // For each wakeable, attach a listener so that when it resolves, React
  // attempts to re-render the boundary in the primary (pre-timeout) state.
  const retryCache = getRetryCache(finishedWork);
  wakeables.forEach(wakeable => {
    // Memoize using the boundary fiber to prevent redundant listeners.
    if (!retryCache.has(wakeable)) {

View on GitHub (pinned to eafeac097b)

Solutions

  1. Update React to the latest stable/canary - retry-cache handling changed several times
  2. Reduce the repro around use()/lazy + Suspense retries and file an issue
  3. Check for duplicate React copies if several reconciler versions are installed
  4. As a workaround, resolve suspending data before render instead of throwing promises through these boundaries
Defensive patterns

Strategy: try-catch

Try / catch

Commit-phase throw: route it to onUncaughtError, include the suspended value and boundary layout, report as a React bug, and remount the root.

Prevention

When it happens

Trigger: React internal bugs in wakeable handling - a thenable thrown during reconciliation and attached to a fiber that was later retagged (function-to-class remount, lazy resolution changing the tag mid-flight), or retry logic invoked on a completed non-suspense fiber.

Common situations: Heavy Suspense usage with thrown promises (React 19 thenables, use()); lazy components resolving during a retry pass; DevTools remounts while suspended; appears on specific canary versions.

Related errors


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