Fetch with setTimeout fails during prerendering?

canary
1ea5b07Remove loadConfig from main development process, pass value from child process (#88230)
This post might have stale content, as canary is 34 commits ahead.

I'm getting this error at build time when prerendering some of the pages defined in the generateStaticParams:

Error: During prerendering, fetch() rejects when the prerender is complete. Typically these errors are handled by React but if you move fetch() to a different context by using setTimeout, after, or similar functions you may observe this error and you should handle it in that context.

This means the page can't have a fetch with exponential backoffs because the implementation uses setTimeout?

Avatar of Claude Haiku 4.5Claude Haiku 4.5commented

This is a good question about how prerendering works in Next.js. Let me search the codebase to understand the error message and the constraints around fetch during prerendering.

Let me try a broader search:

Perfect! Now let me look at the dynamic-rendering-utils.ts file to understand the context:

Now let me look at the test case to understand how this error manifests:

Let me check the test fixtures to see what scenarios trigger this:

Now let me search for how fetch is specifically handled during prerendering:

Let me look at the patch-fetch.ts file since that's where fetch is being patched:

Let me continue reading to find where fetch is being handled during prerendering:

Perfect! Now I can see how it works. Let me search for documentation about this behavior:

Let me check the errors documentation:

Based on my exploration of the Next.js codebase, I can now answer your question clearly:

##Summary

Yes, you've correctly identified the issue. The error you're seeing means that your page cannot use fetch() with exponential backoff retry logic that relies on setTimeout when prerendering.

##What's happening

During prerendering (static generation), Next.js uses a mechanism called "hanging promises" to track dynamic API usage. Here's how it works:

  1. When your page prerendering completes, Next.js triggers an AbortSignal that causes all pending requests (like fetch() calls) to immediately reject with the error you're seeing.

  2. The problem with exponential backoff: If your retry logic uses setTimeout to delay the next fetch attempt:

    • The first fetch() happens during prerendering
    • The prerendering completes, triggering the abort signal
    • Your setTimeout callback fires later and tries to call fetch() again
    • But by then, prerendering is complete, so the new fetch() immediately rejects with your error
  3. Why React can normally handle this: React has built-in error boundaries that would normally catch these rejections, but since you've moved the code into a different async context via setTimeout, React can't catch it, and you see the unhandled error.

##Code location

From the source code (packages/next/src/server/lib/patch-fetch.ts lines 552 and 678), when Next.js detects a dynamic fetch requirement during prerendering, it returns:

return makeHangingPromise<Response>(
  workUnitStore.renderSignal,
  workStore.route,
  'fetch()'
)

This creates a promise that always rejects when prerendering is complete, regardless of when you try to await it.

##Solutions

  1. Move retry logic outside of prerendering: Use revalidateTag() or on-demand revalidation instead of runtime retries
  2. Use unstable_noStore(): Mark the page as dynamic so it doesn't prerender
  3. Handle the error properly: If you must retry, catch the error in the same async context where it occurs, not in a deferred callback
  4. Use server-side caching: Cache successful responses and avoid retry logic during static generation

END OF POST

Log in to add a comment
Claude Haiku 4.5
Fetch with setTimeout fails during prerendering? — vercel/next.js