Skip to content

fix(cli): set non-zero exit code on argument errors#60923

Merged
altaywtf merged 6 commits into
openclaw:mainfrom
Linux2010:fix/60905-cli-exit-code-on-error
Apr 5, 2026
Merged

fix(cli): set non-zero exit code on argument errors#60923
altaywtf merged 6 commits into
openclaw:mainfrom
Linux2010:fix/60905-cli-exit-code-on-error

Conversation

@Linux2010

@Linux2010 Linux2010 commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #60905

When CLI commands receive invalid arguments (e.g., openclaw sessions list), Commander.js prints an error but was returning exit code 0. This broke scripts and monitoring tools that rely on exit codes to detect failures.

Solution

Call program.exitOverride() with a callback that sets process.exitCode = 1 for all errors except help/version displays.

Before

$ openclaw sessions list 2>&1
error: too many arguments for 'sessions'. Expected 0 arguments but got 1.
$ echo $?
0

After

$ openclaw sessions list 2>&1
error: too many arguments for 'sessions'. Expected 0 arguments but got 1.
$ echo $?
1

Test Coverage

Added 3 new unit tests to verify exit code behavior:

  • ✅ Argument errors set exitCode = 1
  • --help sets exitCode = 0 (handles commander.helpDisplayed)
  • --version sets exitCode = 0

Test Plan

  • Unit tests pass: pnpm test src/cli/program/build-program.test.ts
  • Manual test confirms exit code is now 1 on argument errors
  • Help (--help) still exits with code 0
  • Version (--version) still exits with code 0

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes size: XS labels Apr 4, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c820715598

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/cli/program/build-program.ts Outdated
@Linux2010 Linux2010 force-pushed the fix/60905-cli-exit-code-on-error branch from c820715 to f0e3fd7 Compare April 4, 2026 15:37
@greptile-apps

greptile-apps Bot commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a long-standing CLI bug where openclaw sessions list (and similar invalid invocations) would print a Commander error but still exit with code 0, breaking scripts and monitoring tools. The fix registers an exitOverride callback on the Commander Program that sets process.exitCode from the Commander error's own exit code and rethrows the error, cleanly aborting the parse.

The implementation correctly addresses both concerns raised in the prior review round:

  • The callback now rethrows so Commander's parse is aborted and action handlers do not run after an argument error.
  • The callback no longer contains special-cased dead-code branches for commander.version; it simply mirrors err.exitCode for every error code.

Key observations:

  • src/cli/program/build-program.ts: Clean and minimal. The exitOverride callback sets process.exitCode (with a fallback to 1 if exitCode is not a number) then rethrows.
  • src/cli/run-main.ts: The existing try/catch around program.parseAsync (lines 235-242) now activates for Commander errors because exitOverride throws. It redundantly re-sets process.exitCode = error.exitCode, which is harmless since it is the same value that exitOverride already wrote.
  • src/cli/program/build-program.test.ts: The new \"does not run the command action after an argument error\" test is the most important addition — it directly validates the abort-before-action behavior that was the crux of the original issue.
  • src/cli/run-main.exit.test.ts: New integration-level test file; enableConsoleCapture and installUnhandledRejectionHandler are invoked with real implementations (both have global side effects), as noted in the inline comment."

Confidence Score: 5/5

Safe to merge — the logic fix is correct, the prior P1 rethrow concern is resolved, and no new correctness issues were found.

All remaining findings are P2 style/test-isolation concerns. The core behavior (setting exit code, aborting parse before running the action handler) is verified by the new unit tests. No P0 or P1 issues remain.

src/cli/run-main.exit.test.ts — missing mocks for enableConsoleCapture and installUnhandledRejectionHandler could cause test contamination across the suite.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/cli/run-main.exit.test.ts
Line: 170-186

Comment:
**Missing mocks for side-effectful imports in integration test**

The `"swallows Commander parse exits"` test exercises the full `runCli` code path through the Commander `parseAsync` call, which means two un-mocked modules are invoked with their real implementations:

1. **`enableConsoleCapture`** (static import from `../logging.js`, called at `run-main.ts:175`) — patches global `console.*` methods and registers EPIPE listeners on `process.stdout`/`process.stderr`. These patches persist for the lifetime of the test process.

2. **`installUnhandledRejectionHandler`** (dynamically imported from `../infra/unhandled-rejections.js`, called at `run-main.ts:183`) — attaches a `process.unhandledRejection` listener that can invoke `process.exit(1)` for fatal rejections. Because the listener is never removed, it remains active in all subsequent tests in the same process.

Neither module appears in the `vi.mock()` list for this file. Mocking both would prevent global console patching and stop the persistent `unhandledRejection` listener from triggering unexpected exits in other tests.

```ts
vi.mock("../logging.js", () => ({ enableConsoleCapture: vi.fn() }));
vi.mock("../infra/unhandled-rejections.js", () => ({
  installUnhandledRejectionHandler: vi.fn(),
}));
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (3): Last reviewed commit: "cli: silence commander tests and rethrow..." | Re-trigger Greptile

Comment thread src/cli/program/build-program.ts
Comment thread src/cli/program/build-program.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f0e3fd7057

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/cli/program/build-program.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1659b04c28

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/cli/program/build-program.ts Outdated
@altaywtf altaywtf self-assigned this Apr 4, 2026
@altaywtf altaywtf force-pushed the fix/60905-cli-exit-code-on-error branch 2 times, most recently from 3e99fe1 to 8c10f0e Compare April 4, 2026 21:42
@altaywtf altaywtf requested a review from Copilot April 4, 2026 21:43
@altaywtf

altaywtf commented Apr 4, 2026

Copy link
Copy Markdown
Member

@greptileai review

Copilot AI left a comment

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.

Pull request overview

This PR fixes a CLI regression where Commander.js printed argument/usage errors but the process still exited with code 0, which breaks scripting/monitoring that relies on non-zero exit codes for failures.

Changes:

  • Add a program.exitOverride handler to ensure process.exitCode is set based on Commander’s computed err.exitCode (defaulting to 1).
  • Add unit tests covering argument errors, help/version exits, and help error paths (including { from: "user" } parsing).
  • Document the behavior change in CHANGELOG.md.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/cli/program/build-program.ts Sets process.exitCode during Commander exit flows to preserve correct non-zero codes for argument/help-error paths.
src/cli/program/build-program.test.ts Adds regression tests validating exit code behavior when process.exit is intercepted.
CHANGELOG.md Records the CLI/Commander exit-code fix and the added regression coverage.

Comment thread src/cli/program/build-program.test.ts
@altaywtf altaywtf force-pushed the fix/60905-cli-exit-code-on-error branch 2 times, most recently from 8ba7616 to 793ed27 Compare April 4, 2026 22:37
@altaywtf

altaywtf commented Apr 4, 2026

Copy link
Copy Markdown
Member

@greptileai review

@altaywtf altaywtf force-pushed the fix/60905-cli-exit-code-on-error branch from 9f23926 to a783109 Compare April 5, 2026 00:14
Linux2010 and others added 6 commits April 5, 2026 03:16
Fixes openclaw#60905

When CLI commands receive invalid arguments (e.g., `openclaw sessions list`),
Commander.js prints an error but was returning exit code 0. This broke
scripts and monitoring tools that rely on exit codes to detect failures.

Solution: Call `program.exitOverride()` with a callback that sets
`process.exitCode = 1` for all errors except help/version displays.

Before:
```bash
$ openclaw sessions list 2>&1
error: too many arguments...
$ echo $?
0
```

After:
```bash
$ openclaw sessions list 2>&1
error: too many arguments...
$ echo $?
1
```
Add unit tests to verify:
- Argument errors set exitCode = 1
- --help sets exitCode = 0 (commander.helpDisplayed)
- --version sets exitCode = 0 (commander.version)

Also fix exitOverride to handle commander.helpDisplayed in addition
to commander.help for proper help display handling.
@altaywtf altaywtf force-pushed the fix/60905-cli-exit-code-on-error branch from a783109 to 0de0c43 Compare April 5, 2026 00:17
@altaywtf altaywtf merged commit dca2156 into openclaw:main Apr 5, 2026
8 checks passed
@altaywtf

altaywtf commented Apr 5, 2026

Copy link
Copy Markdown
Member

Merged via squash.

Thanks @Linux2010!

lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
Merged via squash.

Prepared head SHA: 0de0c43
Co-authored-by: Linux2010 <35169750+Linux2010@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
Merged via squash.

Prepared head SHA: 0de0c43
Co-authored-by: Linux2010 <35169750+Linux2010@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
Merged via squash.

Prepared head SHA: 0de0c43
Co-authored-by: Linux2010 <35169750+Linux2010@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
Merged via squash.

Prepared head SHA: 0de0c43
Co-authored-by: Linux2010 <35169750+Linux2010@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: openclaw sessions list returns exit code 0 despite error output

3 participants