mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-20 06:20:55 +00:00
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 2b1d1985ef)
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