From 6314c949c71f47b6f2b2a868fc547a8be0c7b9a7 Mon Sep 17 00:00:00 2001 From: Aditya Mathur <57684218+MathurAditya724@users.noreply.github.com> Date: Fri, 5 Jun 2026 02:31:10 +0000 Subject: [PATCH] fix(local): re-emit SIGINT/SIGTERM after cleanup in verify mode SIGINT during --verify or post-init verification was forwarded to the child process but never re-emitted, so the CLI continued normally after cleanup instead of terminating. Track the received signal and re-emit it via process.kill(process.pid, signal) after all cleanup (child kill, server shutdown, listener removal) completes. --- src/commands/local/run.ts | 18 ++++++++++++++++-- src/lib/init/verify-setup.ts | 21 +++++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/commands/local/run.ts b/src/commands/local/run.ts index 03642dfc7..ed2556386 100644 --- a/src/commands/local/run.ts +++ b/src/commands/local/run.ts @@ -406,8 +406,15 @@ async function* runWithVerify( ); } - const onSigint = () => child.kill("SIGINT"); - const onSigterm = () => child.kill("SIGTERM"); + let signalReceived: NodeJS.Signals | null = null; + const onSigint = () => { + signalReceived = "SIGINT"; + child.kill("SIGINT"); + }; + const onSigterm = () => { + signalReceived = "SIGTERM"; + child.kill("SIGTERM"); + }; process.once("SIGINT", onSigint); process.once("SIGTERM", onSigterm); @@ -465,6 +472,13 @@ async function* runWithVerify( await shutdownServer(server); } + // Re-emit the signal after cleanup so the default handler terminates the + // process instead of continuing with the outcome switch below. + if (signalReceived) { + process.kill(process.pid, signalReceived); + return; + } + switch (outcome.kind) { case "envelope": { logger.info("Setup verified — your app is sending events to Sentry"); diff --git a/src/lib/init/verify-setup.ts b/src/lib/init/verify-setup.ts index 20e4bf0ed..a2c86d5f1 100644 --- a/src/lib/init/verify-setup.ts +++ b/src/lib/init/verify-setup.ts @@ -282,6 +282,9 @@ export async function verifySetup( return; } + // Track whether the user sent an interrupt so we can re-emit it after + // cleanup instead of silently continuing the wizard. + let signalReceived: NodeJS.Signals | null = null; const safeKill = (sig: NodeJS.Signals) => { try { child.kill(sig); @@ -289,8 +292,14 @@ export async function verifySetup( logger.debug(`Child already exited when forwarding ${sig}`); } }; - const onSigint = () => safeKill("SIGINT"); - const onSigterm = () => safeKill("SIGTERM"); + const onSigint = () => { + signalReceived = "SIGINT"; + safeKill("SIGINT"); + }; + const onSigterm = () => { + signalReceived = "SIGTERM"; + safeKill("SIGTERM"); + }; process.once("SIGINT", onSigint); process.once("SIGTERM", onSigterm); @@ -333,6 +342,14 @@ export async function verifySetup( process.removeListener("SIGTERM", onSigterm); await shutdownServer(server); + // Re-emit the signal after cleanup so the default handler terminates the + // process. Without this, Ctrl+C during verification would be swallowed and + // the wizard would continue as if nothing happened. + if (signalReceived) { + process.kill(process.pid, signalReceived); + return; + } + // If the child crashed (non-zero exit) but the startup watcher resolved // first as "started" or "silent", correct to "exited" so the crash is // reported instead of a false success or misleading timeout message.