facebook/react · warning · Error

489

489

Error message

Expected the resume to render <${node[0]}> in this slot but instead it rendered <${name}>. The tree doesn't match so React will fallback to client rendering.

What it means

During resume, a slot recorded at prerender time expected a component named X (stored as node[0]), but the resumed render produced a component with a different name at the same key/index. As a precaution React verifies the name matches; on mismatch it throws error code 489 and the boundary falls back to client rendering.

Source

Thrown at packages/react-server/src/ReactFizzServer.js:3256

  childIndex: number,
  type: any,
  props: Object,
  ref: any,
  replay: ReplaySet,
): void {
  // We're replaying. Find the path to follow.
  const replayNodes = replay.nodes;
  for (let i = 0; i < replayNodes.length; i++) {
    // Flow doesn't support refinement on tuples so we do it manually here.
    const node = replayNodes[i];
    if (keyOrIndex !== node[1]) {
      continue;
    }
    if (node.length === 4) {
      // Matched a replayable path.
      // Let's double check that the component name matches as a precaution.
      if (name !== null && name !== node[0]) {
        throw new Error(
          'Expected the resume to render <' +
            (node[0] as any) +
            '> in this slot but instead it rendered <' +
            name +
            '>. ' +
            "The tree doesn't match so React will fallback to client rendering.",
        );
      }
      const childNodes = node[2];
      const childSlots = node[3];
      const currentNode = task.node;
      task.replay = {nodes: childNodes, slots: childSlots, pendingTasks: 1};
      try {
        renderElement(request, task, keyPath, type, props, ref);
        if (
          task.replay.pendingTasks === 1 &&
          task.replay.nodes.length > 0
          // TODO check remaining slots

View on GitHub (pinned to eafeac097b)

Solutions

  1. Render the same component at each slot in both passes (pin code versions between prerender and resume)
  2. Keep the component at the slot stable and vary only its props instead of its identity
  3. Move flag-dependent component choices behind a postponed or client-rendered boundary
  4. Regenerate the prerendered payload after renaming or swapping components

Example fix

// before
// prerender: <OldButton>; resume (flag flipped): <NewButton> in the same slot -> throws
return flag ? <NewButton /> : <OldButton />;

// after
// keep one stable component at the slot and vary props
return <Button variant={flag ? 'new' : 'old'} />;
Defensive patterns

Strategy: fallback

Try / catch

// React catches this and client-renders the boundary; no user try/catch needed.
// Log via the render/resume error hooks:
//   onError(err) { log.warn('slot component mismatch -> client fallback:', err.message); }

Prevention

When it happens

Trigger: The component at a given position changed identity between prerender and resume: a renamed component, a dynamic import resolving to a different implementation, an A/B flag flipping the branch, or a different dependency version in the resume environment.

Common situations: Deploying renamed components while resuming old prerendered payloads; per-request feature flags choosing different components; vendored vs npm versions of a component resolving differently.

Related errors


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