fix(exec): treat shell exit codes 126/127 as failures instead of completed
When a command exits with code 127 (command not found) or 126 (not executable), the exec tool previously returned status "completed" with the error buried in the output text. This caused cron jobs to report status "ok" and never increment consecutiveErrors, silently swallowing failures like `python: command not found` across multiple daily cycles. Now these shell-reserved exit codes are classified as "failed", which propagates through the cron pipeline to properly increment consecutiveErrors and surface the issue for operator attention. Fixes #24587 Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 2b1d1985ef09000977131bbb1a5c2d732b6cd6e4)
This commit is contained in:
committed by
Peter Steinberger
parent
c6bb7b0c04
commit
f3459d71e8
@@ -482,7 +482,13 @@ export async function runExecProcess(opts: {
|
||||
.then((exit): ExecProcessOutcome => {
|
||||
const durationMs = Date.now() - startedAt;
|
||||
const isNormalExit = exit.reason === "exit";
|
||||
const status: "completed" | "failed" = isNormalExit ? "completed" : "failed";
|
||||
const exitCode = exit.exitCode ?? 0;
|
||||
// Shell exit codes 126 (not executable) and 127 (command not found) are
|
||||
// unrecoverable infrastructure failures that should surface as real errors
|
||||
// rather than silently completing — e.g. `python: command not found`.
|
||||
const isShellFailure = exitCode === 126 || exitCode === 127;
|
||||
const status: "completed" | "failed" =
|
||||
isNormalExit && !isShellFailure ? "completed" : "failed";
|
||||
|
||||
markExited(session, exit.exitCode, exit.exitSignal, status);
|
||||
maybeNotifyOnExit(session, status);
|
||||
@@ -491,7 +497,6 @@ export async function runExecProcess(opts: {
|
||||
}
|
||||
const aggregated = session.aggregated.trim();
|
||||
if (status === "completed") {
|
||||
const exitCode = exit.exitCode ?? 0;
|
||||
const exitMsg = exitCode !== 0 ? `\n\n(Command exited with code ${exitCode})` : "";
|
||||
return {
|
||||
status: "completed",
|
||||
@@ -502,8 +507,11 @@ export async function runExecProcess(opts: {
|
||||
timedOut: false,
|
||||
};
|
||||
}
|
||||
const reason =
|
||||
exit.reason === "overall-timeout"
|
||||
const reason = isShellFailure
|
||||
? exitCode === 127
|
||||
? "Command not found"
|
||||
: "Command not executable (permission denied)"
|
||||
: exit.reason === "overall-timeout"
|
||||
? typeof opts.timeoutSec === "number" && opts.timeoutSec > 0
|
||||
? `Command timed out after ${opts.timeoutSec} seconds`
|
||||
: "Command timed out"
|
||||
|
||||
Reference in New Issue
Block a user