Summary
In production builds, Server Component render errors are silently swallowed. rscOnError generates a digest but never logs or reports the original error, and reportRequestError is a no-op in the production entry point. This makes it impossible for error-tracking services (e.g. Sentry) to capture the real error — they only see the sanitised message React sends to the client:
"An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details."
Details
rscOnError doesn't log errors
In the production bundle, rscOnError only generates a digest hash and returns it. For Error instances it never calls console.error, reportRequestError, or any other reporting mechanism:
// From the built output (dist/server/assets/worker-entry-*.js)
function rscOnError(error2) {
if (error2 && typeof error2 === "object" && "digest" in error2) {
return String(error2.digest);
}
if (error2) {
const msg = error2 instanceof Error ? error2.message : String(error2);
const stack = error2 instanceof Error ? error2.stack || "" : "";
return __errorDigest(msg + stack);
}
return void 0;
}
Compare this to the dev server (app-dev-server.ts) which calls _reportRequestError(error) for server actions — but even there, rscOnError itself doesn't report errors.
reportRequestError is a no-op in production
The production entry point (prod-server.js) contains:
async function reportRequestError(error2, request, context) {
return;
}
Even if rscOnError were to call reportRequestError, it would do nothing. The instrumentation.ts onRequestError hook is loaded but never wired into the production code path.
Expected behaviour
rscOnError should call console.error(error) (like React's own SSR renderer does) and/or call reportRequestError so the original error is observable
reportRequestError should actually invoke onRequestError from instrumentation.ts in production builds, not be a no-op
- The
onRequestError instrumentation hook should be wired into the production entry point
Workaround
We're using a Vite renderChunk plugin to patch rscOnError in the final bundle to inject console.error(error), combined with Sentry's captureConsoleIntegration to capture those as events:
function vinextRscErrorReporting(): Plugin {
return {
name: "vinext-rsc-error-reporting",
renderChunk(code) {
if (!code.includes("function rscOnError(")) return;
const patched = code.replace(
/function rscOnError\((\w+)\)\s*\{([\s\S]*?)return __errorDigest\((\w+) \+ (\w+)\);/,
(match, errorVar, before, msgVar, stackVar) =>
`function rscOnError(${errorVar}) {${before}` +
`console.error(${errorVar});\n` +
` return __errorDigest(${msgVar} + ${stackVar});`,
);
if (patched !== code) return { code: patched, map: null };
},
};
}
This is fragile and will break if vinext's internal code generation changes
Summary
In production builds, Server Component render errors are silently swallowed.
rscOnErrorgenerates a digest but never logs or reports the original error, andreportRequestErroris a no-op in the production entry point. This makes it impossible for error-tracking services (e.g. Sentry) to capture the real error — they only see the sanitised message React sends to the client:Details
rscOnErrordoesn't log errorsIn the production bundle,
rscOnErroronly generates a digest hash and returns it. ForErrorinstances it never callsconsole.error,reportRequestError, or any other reporting mechanism:Compare this to the dev server (
app-dev-server.ts) which calls_reportRequestError(error)for server actions — but even there,rscOnErroritself doesn't report errors.reportRequestErroris a no-op in productionThe production entry point (
prod-server.js) contains:Even if
rscOnErrorwere to callreportRequestError, it would do nothing. Theinstrumentation.tsonRequestErrorhook is loaded but never wired into the production code path.Expected behaviour
rscOnErrorshould callconsole.error(error)(like React's own SSR renderer does) and/or callreportRequestErrorso the original error is observablereportRequestErrorshould actually invokeonRequestErrorfrominstrumentation.tsin production builds, not be a no-oponRequestErrorinstrumentation hook should be wired into the production entry pointWorkaround
We're using a Vite
renderChunkplugin to patchrscOnErrorin the final bundle to injectconsole.error(error), combined with Sentry'scaptureConsoleIntegrationto capture those as events:This is fragile and will break if vinext's internal code generation changes