Skip to content

fix: fail the build when React reports a render error - #195

Merged
uhyo merged 1 commit into
masterfrom
fix/fail-build-on-render-error
Oct 18, 2026
Merged

uhyo merged 1 commit into
masterfrom
fix/fail-build-on-render-error

Conversation

@uhyo

@uhyo uhyo commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Closes #194

Summary

React does not stop when a page fails to render. It puts an E row in the RSC payload, or with SSR, leaves the affected <Suspense> boundary to render on the client (<!--$!-->). Its default onError only calls console.error. So vite build wrote the broken page and exited 0, and a static site has no later request that could fix the page.

This PR passes an onError to every render during the build and fails the build when any error is reported.

  • Error collection. build() in src/rsc/entry.tsx passes onError to the RSC render of each page: the full tree with SSR on; the shell and the App separately with SSR off. It also passes one to renderHTML, which hands it to prerender. Deferred payloads get one through setDeferRenderErrorHandler, and DeferRegistry's render function now receives the defer() name. Each error is logged with what was being rendered (for example RSC payload of "index.html" or deferred component "Throws") and collected. The dev server is unchanged and keeps React's defaults.
  • Failing the build. React keeps reporting errors while the output streams are being read, so buildApp checks after rendering the deferred payloads and after reading each page, before writing it. If errors were collected, it throws an AggregateError that lists each error and where it happened. The affected pages are not written.
  • New option failOnRenderError (default true). Set it to false to log the errors and write the output as before.

Notes

  • With SSR on and no <Suspense> around the failing part, prerender already rejected before this change, so those builds already failed. They still fail with failOnRenderError: false. The error that ends the build there is React's generic "An error occurred in the Server Components render", but the real error is now logged just above it.
  • Client Components that throw during SSR on purpose, to render only in the browser, should use React 19.3's browser() API instead, so failing by default doesn't block that pattern.
  • The issue's optional suggestion of an onError hook for the user's build module is not included.

Tests

  • New fixture e2e/fixture-render-error with four cases: no error, a function passed to a Client Component, a deferred component that throws, and a Client Component that throws during SSR. Environment variables choose the case and options, and each variant builds into its own dist/ subdirectory.
  • New e2e/tests/render-error.spec.ts (Playwright project render-error, no web server) runs vite build for each case with SSR on and off. It checks the exit code and error message, that no index.html is written on failure, and that failOnRenderError: false produces the E row and <!--$!--> as before. All 9 tests pass; against the old code, 7 fail (all but the two no-error cases).
  • Unit tests for renderErrors.ts.
  • pnpm test:run, typecheck, lint, format:check and pnpm build (including docs and example) pass. The existing e2e suites pass: 48 against the production build and 32 against the dev server.

Docs

  • Added the failOnRenderError option to the funstackStatic() API page.
  • The SSR page now notes that errors inside <Suspense> also fail the build.

Generated by Claude Code

During `vite build`, the RSC render, the SSR prerender and deferred
payload renders now get an `onError` handler that logs the error with
its source (entry path or defer name) and records it. React recovers
from these errors in the output (an `E` row in the RSC payload, a
client-rendered Suspense boundary in the HTML), so previously the build
wrote the broken page and exited 0. `buildApp` now fails with an error
listing every collected error before writing the affected output.

Add a `failOnRenderError` option (default `true`); set it to `false` to
only log the errors and emit the output as before.

Closes #194

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FMU5vtU9xKNCD7XzUNDftA
@uhyo
uhyo merged commit 5098a58 into master Oct 18, 2026
2 checks passed
@uhyo
uhyo deleted the fix/fail-build-on-render-error branch October 18, 2026 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build exits 0 when a Server Component or prerender throws; the error is only logged

2 participants