Skip to content

Bug: Resuming a prerender that was aborted while a retried task was rendering drops part of the boundary #37709

Description

@AdzerKI

React version: main (d083ec1), 19.3.0-experimental-cbb046ab-20260731

Steps To Reproduce

  1. Prerender a boundary whose content suspends once, so it gets retried as its own task, and then aborts the prerender synchronously while rendering a later child.
  2. Resume the postponed state.

Link to code example:

let resolve;
const promise = new Promise(r => (resolve = r));
let prerendering = true;
const controller = new AbortController();

function Abort() {
  if (prerendering) {
    controller.abort();
  }
  return 'World';
}

function Content() {
  React.use(promise);
  return (
    <section>
      <span>Hello</span>
      <Abort />
    </section>
  );
}

function App() {
  return (
    <div>
      <Suspense fallback="Loading...">
        <Content />
      </Suspense>
    </div>
  );
}

const pending = prerender(<App />, {signal: controller.signal});
resolve();
const {postponed} = await pending;

prerendering = false;
const stream = await resume(<App />, JSON.parse(JSON.stringify(postponed)));

The current behavior

The resumed boundary contains only the child that was rendering when the prerender was aborted: <div>World</div>.

retryRenderTask rewinds the segment to where the attempt started, but task.keyPath and task.childIndex still point at <Abort /> when the task is finished through abortUnwoundTask. trackPostpone records the hole as slot 1 of <section>, and the resume renders <Abort /> alone into the boundary's segment.

We run into this in Next.js 16 with cacheComponents: reading Date.now() in a Client Component aborts the prerender synchronously, the page boundary resumes empty and hydration fails with #418.

The expected behavior

The hole covers everything the aborted attempt discarded, so the resume renders the whole content: <div><section><span>Hello</span>World</section></div>.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions