From 3e7e709884be17142a24274d36bce41ec2e29e31 Mon Sep 17 00:00:00 2001 From: LukeParkerDev <10430890+Hona@users.noreply.github.com> Date: Fri, 17 Apr 2026 11:28:51 +1000 Subject: [PATCH] fix: preserve full error stacks in desktop renderer logs Electron's console-message event only surfaces {level, message, line, sourceId} without the stack, so uncaught errors showed up as 'line 1028 of chunk-*.js' (SolidJS's rethrow site) with no way to find the real origin. Attach window error and unhandledrejection listeners that log the full stack via console.error, and reshape the main-process log line so newlines in the stack survive instead of being JSON-escaped into one unreadable blob. --- packages/desktop-electron/src/main/index.ts | 12 +++++++---- .../desktop-electron/src/renderer/index.tsx | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts index 84720b3030..f84414a5dc 100644 --- a/packages/desktop-electron/src/main/index.ts +++ b/packages/desktop-electron/src/main/index.ts @@ -258,16 +258,20 @@ async function initialize() { function wireWindowDiagnostics(win: BrowserWindow, label: string) { win.webContents.on("console-message", (_event, level, message, line, sourceId) => { - const payload = { level, message, line, sourceId } + // Render `message` as a block so multi-line stack traces survive; the + // previous shape stuffed the message into a JSON object which escaped + // `\n` and made stacks unreadable. + const location = sourceId ? ` [${sourceId}:${line}]` : "" + const text = `${label} renderer${location}\n${message}` if (level >= 3) { - logger.error(`${label} renderer console`, payload) + logger.error(text) return } if (level >= 2) { - logger.warn(`${label} renderer console`, payload) + logger.warn(text) return } - logger.log(`${label} renderer console`, payload) + logger.log(text) }) win.webContents.on("did-fail-load", (_event, errorCode, errorDescription, validatedURL, isMainFrame) => { diff --git a/packages/desktop-electron/src/renderer/index.tsx b/packages/desktop-electron/src/renderer/index.tsx index aa31dc3b64..79a599f354 100644 --- a/packages/desktop-electron/src/renderer/index.tsx +++ b/packages/desktop-electron/src/renderer/index.tsx @@ -1,5 +1,25 @@ // @refresh reload +// Install global error listeners before any other module runs so that +// uncaught errors and rejected promises reach the main process with their +// full stacks intact. Electron's `console-message` event only forwards the +// rethrow site, so without these we lose the originating frame. +window.addEventListener("error", (event) => { + const err = event.error + const stack = err instanceof Error ? err.stack : null + console.error( + "[renderer uncaught]", + stack ?? event.message, + stack ? "" : `${event.filename}:${event.lineno}:${event.colno}`, + ) +}) + +window.addEventListener("unhandledrejection", (event) => { + const reason = event.reason + const stack = reason instanceof Error ? reason.stack : null + console.error("[renderer unhandled rejection]", stack ?? reason) +}) + import { ACCEPTED_FILE_EXTENSIONS, ACCEPTED_FILE_TYPES,