{"record":{"id":"47c3c57019034d7c","repo":"facebook/react","slug":"435","errorCode":"435","errorMessage":"Unexpected Suspense handler tag (${finishedWork.tag}). This is a bug in React.","messagePattern":"Unexpected Suspense handler tag \\((.+?)\\)\\. This is a bug in React\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-reconciler/src/ReactFiberCommitWork.js","lineNumber":1970,"sourceCode":"    case SuspenseComponent:\n    case SuspenseListComponent: {\n      let retryCache = finishedWork.stateNode;\n      if (retryCache === null) {\n        retryCache = finishedWork.stateNode = new PossiblyWeakSet();\n      }\n      return retryCache;\n    }\n    case OffscreenComponent: {\n      const instance: OffscreenInstance = finishedWork.stateNode;\n      let retryCache: null | Set<Wakeable> | WeakSet<Wakeable> =\n        instance._retryCache;\n      if (retryCache === null) {\n        retryCache = instance._retryCache = new PossiblyWeakSet();\n      }\n      return retryCache;\n    }\n    default: {\n      throw new Error(\n        `Unexpected Suspense handler tag (${finishedWork.tag}). This is a ` +\n          'bug in React.',\n      );\n    }\n  }\n}\n\nfunction attachSuspenseRetryListeners(\n  finishedWork: Fiber,\n  wakeables: RetryQueue,\n) {\n  // If this boundary just timed out, then it will have a set of wakeables.\n  // For each wakeable, attach a listener so that when it resolves, React\n  // attempts to re-render the boundary in the primary (pre-timeout) state.\n  const retryCache = getRetryCache(finishedWork);\n  wakeables.forEach(wakeable => {\n    // Memoize using the boundary fiber to prevent redundant listeners.\n    if (!retryCache.has(wakeable)) {","sourceCodeStart":1952,"sourceCodeEnd":1988,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-reconciler/src/ReactFiberCommitWork.js#L1952-L1988","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"Commit-phase throw: route it to onUncaughtError, include the suspended value and boundary layout, report as a React bug, and remount the root.","preventionTips":["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"],"tags":["suspense","retry","wakeable","invariant"],"backgroundTag":"react-internal-invariant","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}