codex - 💡(How to fix) Fix npm shims exit 0 when mirrored child signal is re-caught by the parent

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

If the native child exits because of SIGTERM, SIGINT, or SIGHUP, the npm shim parent should also terminate from the same signal so shell scripts and supervisors observe the correct signal/exit semantics.

Fix Action

Fix / Workaround

Store the installed signal handlers and remove them immediately before re-emitting the child's signal to the parent process. I have a local patch that applies this to both npm shims and adds a Node built-in test that creates temporary fake native binaries and asserts that the parent process exits with signal === "SIGTERM".

Code Example

node --input-type=module -e 'import { spawn } from "node:child_process"; const child = spawn(process.execPath, ["-e", "setTimeout(()=>{}, 10000)"]); const forwardSignal = (signal) => { if (!child.killed) child.kill(signal); }; ["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => process.on(sig, () => forwardSignal(sig))); child.kill("SIGTERM"); const childResult = await new Promise((resolve) => child.on("exit", (code, signal) => resolve(signal ? { type: "signal", signal } : { type: "code", exitCode: code ?? 1 }))); if (childResult.type === "signal") process.kill(process.pid, childResult.signal); else process.exit(childResult.exitCode);'; echo $?

---

pnpm test:node-shims
node --check tests/node_shim_signals.test.js
node --check codex-cli/bin/codex.js
node --check codex-rs/responses-api-proxy/npm/bin/codex-responses-api-proxy.js
pnpm dlx prettier@3.5.3 --check package.json codex-cli/bin/codex.js codex-rs/responses-api-proxy/npm/bin/codex-responses-api-proxy.js tests/node_shim_signals.test.js
git diff --check
RAW_BUFFERClick to expand / collapse

What happened?

The npm JavaScript shims for codex and codex-responses-api-proxy try to mirror a native child process termination signal by calling process.kill(process.pid, childResult.signal) after the child exits due to a signal.

However, the same process still has signal forwarding handlers installed for SIGINT, SIGTERM, and SIGHUP. When the parent sends the signal to itself, its own handler catches that signal and forwards it to the already-exited child instead of letting Node terminate with signal semantics. The parent can then fall off the end of the module and exit successfully.

Reproduction

A minimal reproduction of the current signal-mirroring pattern exits with status 0 after the child exits from SIGTERM:

node --input-type=module -e 'import { spawn } from "node:child_process"; const child = spawn(process.execPath, ["-e", "setTimeout(()=>{}, 10000)"]); const forwardSignal = (signal) => { if (!child.killed) child.kill(signal); }; ["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => process.on(sig, () => forwardSignal(sig))); child.kill("SIGTERM"); const childResult = await new Promise((resolve) => child.on("exit", (code, signal) => resolve(signal ? { type: "signal", signal } : { type: "code", exitCode: code ?? 1 }))); if (childResult.type === "signal") process.kill(process.pid, childResult.signal); else process.exit(childResult.exitCode);'; echo $?

Observed: 0

Expected behavior

If the native child exits because of SIGTERM, SIGINT, or SIGHUP, the npm shim parent should also terminate from the same signal so shell scripts and supervisors observe the correct signal/exit semantics.

Proposed fix

Store the installed signal handlers and remove them immediately before re-emitting the child's signal to the parent process. I have a local patch that applies this to both npm shims and adds a Node built-in test that creates temporary fake native binaries and asserts that the parent process exits with signal === "SIGTERM".

Local validation performed:

pnpm test:node-shims
node --check tests/node_shim_signals.test.js
node --check codex-cli/bin/codex.js
node --check codex-rs/responses-api-proxy/npm/bin/codex-responses-api-proxy.js
pnpm dlx [email protected] --check package.json codex-cli/bin/codex.js codex-rs/responses-api-proxy/npm/bin/codex-responses-api-proxy.js tests/node_shim_signals.test.js
git diff --check

I noticed the repository currently accepts external code PRs by invitation only, so I am filing this issue first per docs/contributing.md.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

If the native child exits because of SIGTERM, SIGINT, or SIGHUP, the npm shim parent should also terminate from the same signal so shell scripts and supervisors observe the correct signal/exit semantics.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

codex - 💡(How to fix) Fix npm shims exit 0 when mirrored child signal is re-caught by the parent