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
- Update React to the latest stable/canary - retry-cache handling changed several times
- Reduce the repro around use()/lazy + Suspense retries and file an issue
- Check for duplicate React copies if several reconciler versions are installed
- 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
- Keep one copy of react across the bundle
- Pin and test canary versions in a staging environment before adopting use()/thenables broadly
- Wrap Suspense-heavy roots with error reporting so repros include the component stack
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
- The should not be any remaining suspense node children if th
- There should always be an Offscreen Fiber child in a hydrate
- A dehydrated Suspense node should not have a content Fiber.
- Encountered a dehydrated Suspense boundary that was previous
- Attempted to measure a Suspense node that does not exist.
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/47c3c57019034d7c.
Report an issue: GitHub.