TanStack / TanStack/router

prerender: retryCount never retries, and a failed page exits the build with code 0

Open
#8,120 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
15.1k
Forks
1.9k
Avg merge
1d 20h
Merged PRs (30d)
143

Description

Which project does this relate to?

Start

Describe the bug

We prerender a full site (774 pages) from a CMS at build time, so a build that fails must fail loudly — a CMS hiccup during the build must never ship a site with missing pages. While hardening that, we found that the prerenderer cannot deliver this promise: a page whose loader throws is logged, announced for a retry that never happens, and the build exits 0 with the page missing from the output. We carry a process.on("unhandledRejection") guard in vite.config.ts to compensate. Two bugs in start-plugin-core/src/prerender.ts:

  1. retryCount never retries. The retry calls addCrawlPageTask(page), which returns early because the path is already in seen. No retry happens, and the error is swallowed (the failOnError branch was not taken). Fix: seen.delete(page.path) before re-adding.
  2. failOnError cannot fail the build. queue.add(...) is never awaited; its rejection becomes an unhandled rejection while Queue.start() resolves via onSettled, which fires on failure too. Vite exits 0. Fix: collect the rejections and rethrow after queue.start().
Complete minimal reproducer

https://github.com/fullheart/tanstack-start-issue-8120

Steps to Reproduce the Bug or Issue

npm install && npm run build; echo $? — the log shows one loader attempt, prints Encountered error, retrying: /broken in 500ms, never retries, and exits 0; .output/public/broken/index.html does not exist. npm run check asserts all three.

Expected behavior

retryCount: 2 attempts the page three times; if it still fails, failOnError: true makes the build exit non-zero.

Additional context

Workaround until fixed — in vite.config.ts, make the swallowed rejection loud, and put retries into your own data layer instead of retryCount:

process.on("unhandledRejection", (error) => {
  console.error(error);
  process.exit(1);
});
Platform
  • Router / Start Version: @tanstack/react-start 1.168.46
  • OS: Linux
  • Bundler: vite
  • Bundler Version: 8.1.5

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with start-plugin-core/src/prerender.ts and run the reported npm run check reproduction. Trace addCrawlPageTask, retryCount, seen, queue.add, and queue.start, then verify that retryCount: 2 makes three attempts and failOnError: true causes npm run build to exit non-zero when the page remains failed.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript, vite
Domain
build-system
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.