From b84853ffe5ac285ce36d530d84d5541f17b11ca4 Mon Sep 17 00:00:00 2001 From: Matin Gathani Date: Wed, 8 Jul 2026 12:17:12 +0530 Subject: [PATCH] [wrangler] fix: report non-zero exit code when killed by a signal (e.g. OOM) bin/wrangler.js's spawn().on("exit", ...) handler ignored the signal argument entirely, treating a signal-killed child (code === null) the same as a clean exit and calling process.exit(0). This made CI pipelines believe wrangler succeeded when it was actually OOM-killed or otherwise terminated by a signal. Now the signal is logged and the shim exits 1. Fixes #14584 --- .changeset/fix-wrangler-signal-exit-code.md | 7 +++++ packages/wrangler/bin/wrangler.js | 16 ++++++++-- .../__tests__/bin-wrangler-exit-code.test.ts | 30 +++++++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 .changeset/fix-wrangler-signal-exit-code.md create mode 100644 packages/wrangler/src/__tests__/bin-wrangler-exit-code.test.ts diff --git a/.changeset/fix-wrangler-signal-exit-code.md b/.changeset/fix-wrangler-signal-exit-code.md new file mode 100644 index 0000000000..8b7fcb7fb5 --- /dev/null +++ b/.changeset/fix-wrangler-signal-exit-code.md @@ -0,0 +1,7 @@ +--- +"wrangler": patch +--- + +Fix `wrangler` reporting exit code 0 when its child process is killed by a signal (e.g. OOM/SIGKILL) + +Previously, if the underlying `wrangler` process was terminated by a signal rather than exiting normally, the CLI wrapper reported exit code 0, making CI pipelines and other automation believe the command succeeded. `wrangler` now reports a non-zero exit code and logs the signal in this case. diff --git a/packages/wrangler/bin/wrangler.js b/packages/wrangler/bin/wrangler.js index 774ecc2ce6..696486e631 100755 --- a/packages/wrangler/bin/wrangler.js +++ b/packages/wrangler/bin/wrangler.js @@ -5,6 +5,16 @@ const path = require("path"); const MIN_NODE_VERSION = "22.0.0"; let wranglerProcess; +function resolveExitCode(code, signal) { + if (code !== null && code !== undefined) { + return code; + } + if (signal) { + console.error(`wrangler exited because it received signal ${signal}`); + } + return 1; +} + /** * Executes ../wrangler-dist/cli.js */ @@ -33,9 +43,7 @@ Consider using a Node.js version manager such as https://volta.sh/ or https://gi stdio: ["inherit", "inherit", "inherit", "ipc"], } ) - .on("exit", (code) => - process.exit(code === undefined || code === null ? 0 : code) - ) + .on("exit", (code, signal) => process.exit(resolveExitCode(code, signal))) .on("message", (message) => { if (process.send) { process.send(message); @@ -89,3 +97,5 @@ if (module === require.main) { wranglerProcess && wranglerProcess.kill(); }); } + +module.exports = { resolveExitCode }; diff --git a/packages/wrangler/src/__tests__/bin-wrangler-exit-code.test.ts b/packages/wrangler/src/__tests__/bin-wrangler-exit-code.test.ts new file mode 100644 index 0000000000..3c23176018 --- /dev/null +++ b/packages/wrangler/src/__tests__/bin-wrangler-exit-code.test.ts @@ -0,0 +1,30 @@ +import { describe, it } from "vitest"; +import { mockConsoleMethods } from "./helpers/mock-console"; + +// eslint-disable-next-line @typescript-eslint/no-require-imports -- bin/wrangler.js is a plain CommonJS script +const { resolveExitCode } = require("../../bin/wrangler.js"); + +describe("bin/wrangler.js resolveExitCode", () => { + const std = mockConsoleMethods(); + + it("passes through a normal numeric exit code", ({ expect }) => { + expect(resolveExitCode(0, null)).toBe(0); + expect(resolveExitCode(1, null)).toBe(1); + }); + + it("reports a non-zero exit code when killed by a signal", ({ expect }) => { + expect(resolveExitCode(null, "SIGKILL")).toBe(1); + expect(std.err).toContain("SIGKILL"); + }); + + it("reports a non-zero exit code for SIGTERM", ({ expect }) => { + expect(resolveExitCode(null, "SIGTERM")).toBe(1); + expect(std.err).toContain("SIGTERM"); + }); + + it("defaults to a non-zero exit code when code and signal are both missing", ({ + expect, + }) => { + expect(resolveExitCode(undefined, null)).toBe(1); + }); +});