From 84731f49b7e8cd109839c6c4f8be9c8f8569a3a4 Mon Sep 17 00:00:00 2001 From: arturovt Date: Fri, 10 Apr 2026 17:46:25 +0300 Subject: [PATCH] fix(platform-server): forward BEFORE_APP_SERIALIZED errors to ErrorHandler Errors thrown by BEFORE_APP_SERIALIZED callbacks were previously logged via console.warn and silently ignored. This meant failures such as TransferState.toJson() encountering a circular reference would go unreported in apps that use a custom ErrorHandler (e.g. Sentry). Errors are now forwarded to the application's ErrorHandler, making them visible through whatever reporting mechanism the app has configured. The render continues to completion after the error is reported. Closes #65811 --- packages/platform-server/src/utils.ts | 9 ++-- .../platform-server/test/integration_spec.ts | 52 ++++++++++++++++++- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/packages/platform-server/src/utils.ts b/packages/platform-server/src/utils.ts index 92baf0b6038b..ac9a746fac96 100644 --- a/packages/platform-server/src/utils.ts +++ b/packages/platform-server/src/utils.ts @@ -17,6 +17,7 @@ import { StaticProvider, Type, ɵannotateForHydration as annotateForHydration, + ɵINTERNAL_APPLICATION_ERROR_HANDLER as INTERNAL_APPLICATION_ERROR_HANDLER, ɵIS_HYDRATION_DOM_REUSE_ENABLED as IS_HYDRATION_DOM_REUSE_ENABLED, ɵSSR_CONTENT_INTEGRITY_MARKER as SSR_CONTENT_INTEGRITY_MARKER, ɵstartMeasuring as startMeasuring, @@ -194,6 +195,7 @@ export async function renderInternal( // Run any BEFORE_APP_SERIALIZED callbacks just before rendering to string. const environmentInjector = applicationRef.injector; + const errorHandler = environmentInjector.get(INTERNAL_APPLICATION_ERROR_HANDLER); const callbacks = environmentInjector.get(BEFORE_APP_SERIALIZED, null); if (callbacks) { const asyncCallbacks: Promise[] = []; @@ -204,15 +206,16 @@ export async function renderInternal( asyncCallbacks.push(callbackResult); } } catch (e) { - // Ignore exceptions. - console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e); + // Delegate to the application's ErrorHandler so custom handlers + // (e.g. Sentry) are notified, rather than writing directly to console. + errorHandler(e); } } if (asyncCallbacks.length) { for (const result of await Promise.allSettled(asyncCallbacks)) { if (result.status === 'rejected') { - console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', result.reason); + errorHandler(result.reason); } } } diff --git a/packages/platform-server/test/integration_spec.ts b/packages/platform-server/test/integration_spec.ts index a40f4fd9ff83..b9de88839d5d 100644 --- a/packages/platform-server/test/integration_spec.ts +++ b/packages/platform-server/test/integration_spec.ts @@ -962,6 +962,52 @@ class HiddenModule {} }, ); + it( + `using ${isStandalone ? 'renderApplication' : 'renderModule'} ` + + `should report to ErrorHandler when TransferState contains an unserializable value (zoneless:${zoneless})`, + async () => { + // A circular reference causes JSON.stringify (called inside toJson()) + // to throw. Previously this was silently swallowed, causing the server + // to return a 200 OK without the