Skip to content

fix(cli): report the real exit code when the binary is killed by a signal - #932

Open
mittalpk wants to merge 2 commits into
alibaba:mainfrom
mittalpk:fix/ocr-signal-exit-code
Open

fix(cli): report the real exit code when the binary is killed by a signal#932
mittalpk wants to merge 2 commits into
alibaba:mainfrom
mittalpk:fix/ocr-signal-exit-code

Conversation

@mittalpk

Copy link
Copy Markdown
Contributor

Fixes #931.

process.exit(result.status ?? (result.error ? 1 : 0)) exits 0 when spawnSync's result has neither status nor error set, which is exactly what happens when the binary gets killed by a signal (OOM etc.) — status is null and there's no spawn error, so a signal-killed run looked like success to any CI/automation gating on exit code. Now it exits with 128 + the signal number, same convention shells use, and prints which signal killed it.

Also pulled the exit-code decision into a small computeExit() function and moved the rest into main() guarded by require.main === module, since the file previously ran everything at require time and couldn't be tested without spawning a real subprocess. Added bin/ocr.test.js covering normal exit, spawn error, and both signal cases.

…gnal

process.exit(result.status ?? (result.error ? 1 : 0)) exits 0 when
spawnSync's result has neither status nor error set, which is
exactly what happens when the native binary is terminated by a
signal (e.g. OOM-killed) -- status is null and there's no spawn
error, so a signal-killed run looked like success to any CI or
automation gating on exit code.

Now exits with 128 + signal number, the same convention shells
use, and prints which signal killed it.

Extracted the exit-code decision into computeExit() and moved the
rest of the script into main(), guarded by require.main === module,
so it's actually testable -- the file previously ran its side
effects at require time, which made it untestable without spawning
a real subprocess.
@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

🔍 OpenCodeReview found 2 issue(s) in this PR.

  • ✅ Successfully posted inline: 2 comment(s)

Comment thread bin/ocr.js
function computeExit(result) {
if (result.signal) {
return {
code: 128 + (os.constants.signals[result.signal] || 1),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maintainability · low
The fallback to signal number 1 (SIGHUP) when the signal name is unrecognized is a defensive choice, but it could produce misleading exit codes. Consider adding a comment explaining why 1 was chosen, or logging a warning for unrecognized signals to aid debugging edge cases.

Comment thread bin/ocr.js Outdated
message: `[ERROR] OpenCodeReview binary was terminated by signal ${result.signal}`,
};
}
return { code: result.status ?? (result.error ? 1 : 0), message: null };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maintainability · medium
When spawnSync itself fails (e.g., EACCES permission denied, or the binary crashes before exec), result.error contains a descriptive Error object, but its message is silently discarded. The user gets exit code 1 with no explanation at all — no stderr from the binary (it never ran) and no error from the wrapper. Since computeExit already has a message field for the signal case, it should also surface the spawn error details. This would significantly aid debugging runtime failures.

Note: the existing test (ocr.test.js line 32) asserts message is null for this case, so the test would also need updating.

Suggestion:

Suggested change
return { code: result.status ?? (result.error ? 1 : 0), message: null };
if (result.error) {
return { code: result.status ?? 1, message: `[ERROR] Failed to run OpenCodeReview binary: ${result.error.message}` };
}
return { code: result.status ?? 0, message: null };

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e57dc75, surfaces result.error.message and updated the test.

When spawnSync itself fails (e.g. EACCES, or the binary crashes before
exec), result.error held a descriptive Error but its message was
silently discarded, leaving the user with exit code 1 and no
explanation. Surface it in the reported message instead.

Also comments the SIGHUP fallback for unrecognized signal names.

Addresses review feedback on alibaba#932.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLI launcher exits 0 when the native binary is killed by a signal (result.status is null)

1 participant