facebook/react · warning · Error
488
488
Error message
Couldn't find all resumable slots by key/index during replaying. The tree doesn't match so React will fallback to client rendering.
What it means
When prerendered SSR output is resumed, React walks recorded replay 'slots' keyed by type and key/index. In replaySuspenseBoundary the server replays a previously postponed Suspense boundary's content; if the replay pass finishes while pendingTasks is still 1 and replay nodes remain, some recorded slots were never matched. React throws error code 488 so the boundary falls back to client rendering instead of emitting a mismatched tree.
Source
Thrown at packages/react-server/src/ReactFizzServer.js:1837
// We can reuse the current context and task to render the content immediately without
// context switching. We just need to temporarily switch which boundary and replay node
// we're writing to. If something suspends, it'll spawn new suspended task with that context.
task.blockedBoundary = resumedBoundary;
task.hoistableState = resumedBoundary.contentState;
task.keyPath = keyPath;
task.formatContext = getSuspenseContentFormatContext(
request.resumableState,
prevContext,
);
task.row = null;
task.replay = {nodes: childNodes, slots: childSlots, pendingTasks: 1};
try {
// We use the safe form because we don't handle suspending here. Only error handling.
renderNode(request, task, content, -1);
if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
throw new Error(
"Couldn't find all resumable slots by key/index during replaying. " +
"The tree doesn't match so React will fallback to client rendering.",
);
}
task.replay.pendingTasks--;
if (
resumedBoundary.pendingTasks === 0 &&
resumedBoundary.status === PENDING
) {
// This must have been the last segment we were waiting on. This boundary is now complete.
// Therefore we won't need the fallback. We early return so that we don't have to create
// the fallback.
resumedBoundary.status = COMPLETED;
request.completedBoundaries.push(resumedBoundary);
// We restore the parent componentStack. Semantically this is the same as
// popComponentStack(task) but we do this instead because it should be slightly
// faster
return;View on GitHub (pinned to eafeac097b)
Solutions
- Make the resumed render produce the identical tree: same keys, same order, same conditionals as the prerender pass
- Move nondeterministic or environment-dependent output behind boundaries that stay postponed, or gate it to the client
- Regenerate the prerendered payload with the same code and config as the resume runtime
- Accept the fallback: ensure a hydration-capable client bundle exists so React can client-render the mismatched boundary
Example fix
// before
{items.map((item) => <Row key={Math.random()} item={item} />)}
// keys differ between prerender and resume -> slots never matched
// after
{items.map((item) => <Row key={item.id} item={item} />)}
// stable keys match the recorded slots on resume Defensive patterns
Strategy: fallback
Try / catch
// Do not try/catch: React converts this error into a client-render fallback for the boundary.
// Observe it through the error hooks of your render/resume API instead:
// onError(err) { log.warn('resume mismatch -> client rendering fallback:', err.message); } Prevention
- Use stable keys and deterministic ordering in anything that resumes
- Run prerender and resume with identical env vars, flags, and code versions
- Keep Date.now()/Math.random()/locale-dependent output out of resumed trees
When it happens
Trigger: Resuming a postponed Suspense boundary whose children render differently than during prerender: different keys, reordered siblings, flipped conditionals, or environment-dependent output between the two passes.
Common situations: Prerendering at build time and resuming in a runtime with different env vars, feature flags, locale, timezone, or random/time-based output; a stale prerendered payload deployed with newer app code.
Related errors
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/6b76af3f47656366.
Report an issue: GitHub.