diff --git a/packages/start-client-core/src/ssr-client.tsx b/packages/start-client-core/src/ssr-client.tsx index b1b43f269a..f99f517052 100644 --- a/packages/start-client-core/src/ssr-client.tsx +++ b/packages/start-client-core/src/ssr-client.tsx @@ -35,6 +35,15 @@ export interface StartSsrGlobal { id: number promiseState: DeferredPromiseState }) => void + rejectPromise: (opts: { + matchId: string + id: number + error: { + message: string + stack?: string + name: string + } + }) => void injectChunk: (opts: { matchId: string; id: number; chunk: string }) => void closeStream: (opts: { matchId: string; id: number }) => void } diff --git a/packages/start-server-core/src/ssr-server.ts b/packages/start-server-core/src/ssr-server.ts index 2c3e897fdf..8c535e3f20 100644 --- a/packages/start-server-core/src/ssr-server.ts +++ b/packages/start-server-core/src/ssr-server.ts @@ -216,20 +216,40 @@ export function onMatchSettled(opts: { function injectPromise(entry: ServerExtractedPromise) { router.serverSsr!.injectScript(async () => { - await entry.promise - - return `__TSR_SSR__.resolvePromise(${jsesc( - { - matchId: match.id, - id: entry.id, - promiseState: entry.promise[TSR_DEFERRED_PROMISE], - } satisfies ResolvePromiseState, - { - isScriptContext: true, - wrap: true, - json: true, - }, - )})` + try { + await entry.promise + + return `__TSR_SSR__.resolvePromise(${jsesc( + { + matchId: match.id, + id: entry.id, + promiseState: entry.promise[TSR_DEFERRED_PROMISE], + } satisfies ResolvePromiseState, + { + isScriptContext: true, + wrap: true, + json: true, + }, + )})` + } catch (error) { + // Serialize and pass errors to the client + return `__TSR_SSR__.rejectPromise(${jsesc( + { + matchId: match.id, + id: entry.id, + error: { + message: error instanceof Error ? error.message : String(error), + stack: error instanceof Error ? error.stack : undefined, + name: error instanceof Error ? error.name : 'Unknown Error', + }, + }, + { + isScriptContext: true, + wrap: true, + json: true, + }, + )})` + } }) } diff --git a/packages/start-server-core/src/tsrScript.ts b/packages/start-server-core/src/tsrScript.ts index 6d3f2c073c..ae6c18effe 100644 --- a/packages/start-server-core/src/tsrScript.ts +++ b/packages/start-server-core/src/tsrScript.ts @@ -58,6 +58,23 @@ const __TSR_SSR__: StartSsrGlobal = { } return false }, + rejectPromise: ({ matchId, id, error }) => { + const match = __TSR_SSR__.matches.find((m) => m.id === matchId) + if (match) { + const ex = match.extracted?.[id] + if (ex && ex.type === 'promise' && ex.value) { + // Rebuild the error object and pass it to the client + const reconstructedError = new Error(error.message) + reconstructedError.name = error.name + if (error.stack) { + reconstructedError.stack = error.stack + } + ex.value.reject(reconstructedError) + return true + } + } + return false + }, injectChunk: ({ matchId, id, chunk }) => { const match = __TSR_SSR__.matches.find((m) => m.id === matchId)