fix(desktop): attach child stderr tail and exit context to host-service crash reports
Why
Sentry DESKTOP-H1 — host-service crashed (signal SIGABRT) — is undiagnosable. The capture in host-service-coordinator.ts sent only the message plus the org id, and SIGABRT is almost certainly a native-module abort, so the child can't self-report. In packaged builds the coordinator handed the rotating log fd straight to the child (stdio: ["ignore", logFd, logFd]), so it never saw a byte of the output either.
DESKTOP-H9 — 'renderer' process exited with 'launch-failed' — has the same problem: our handler logs the full details, but the Sentry event carries none of it.
What changed
host-service crash reports
- Child stdout/stderr are piped through the coordinator and written through to the same rotating
host-service.log(dev keeps its prefixed pass-through tobun dev). Logging behaviour is unchanged; the coordinator can now see the output. - A 16KB rolling tail is kept per child and attached to the crash capture as
outputTail, alongsidepid,uptimeMs(since spawn),respawnAttempts, andversion. Existingexit_code/exit_signaltags are unchanged. - The capture waits 500ms after
exit: piped stdio drains after the process is gone, so capturing synchronously would miss exactly the abort message we're after. - The child's own auth secret is redacted from the tail before it leaves the process. Env is never attached.
errorlisteners on the log stream and the child's stdio, so a failed write can't take down the main process.
renderer crashes
render-process-gone now captures reason and exitCode as tags. Note this is a separate event rather than an enrichment of the SDK's own: @sentry/electron captures from an app-level listener registered at Sentry.init, which fires before this webContents listener, so that event can't be tagged retroactively.
Verification
bunx biome checkclean on the changed files;bun run typecheckshows no new errors (pre-existing failures are unbuilt@superset/chat-legacymodule resolution on main).bun test src/main/lib/— 509 pass, 0 fail.- Ran a standalone harness reproducing the exact spawn/capture pattern against a child that writes app logs and then
process.abort()s (real SIGABRT). With the original 4KB window the ~5KB Node abort backtrace evicted the assertion line itself — that's why the tail is 16KB. At 16KB the captured tail contains the app log line, theAssertion ... failedline, and the full backtrace, with the secret rendered as[redacted]and the log file byte-identical to the child's output.
Trade-off
Production child output now flows through the main process instead of directly to a file, so a wedged main process could apply backpressure to a very chatty child once the 64KB pipe fills. Dev has always run this way, and the handlers drain unconditionally.
What the next SIGABRT will carry
outputTail (last 16KB of the child's own logs and its abort backtrace, secret-redacted), uptimeMs, respawnAttempts, pid, version, plus the existing exit code/signal tags.
Summary by cubic
Improve crash diagnostics by attaching the child process output tail and exit context to host-service crash reports. Also tag renderer process exits with reason and exit code for clearer Sentry events.
- Bug Fixes
- Pipe child stdout/stderr through the coordinator and write through to the rotating log; dev passthrough stays.
- Keep a 16KB rolling output tail and attach to Sentry as outputTail with pid, uptimeMs, respawnAttempts, and app version; wait 500ms post-exit to capture drained output.
- Redact the child’s auth secret from the tail; never include env.
- Add error handlers on log and stdio streams so failed writes don’t crash the main process.
- Capture renderer
render-process-gonevia a separate@sentry/electronevent and tag with reason and exitCode.
Summary by CodeRabbit
- Bug Fixes
- Improved host-service crash reporting with recent process output and detailed exit information.
- Ensured service logs are captured and closed reliably, including after startup failures.
- Added clearer reporting for renderer process terminations, including termination reasons and exit codes.