Skip to content

fix(cli): handle top-level command failures - #8222

Merged
apurvvkumaria merged 12 commits into
mainfrom
fix/8202-top-level-cli-errors
Aug 5, 2026
Merged

fix(cli): handle top-level command failures#8222
apurvvkumaria merged 12 commits into
mainfrom
fix/8202-top-level-cli-errors

Conversation

@sandl99

@sandl99 sandl99 commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

NemoClaw now catches a rejected top-level CLI dispatch. The launcher prints one error line, exits with status 1, and does not expose an uncaught Node.js stack.

Related Issue

Addresses the uncaught-exception cases in #8202.

Changes

  • Catch the launcher's mainPromise rejection.
  • Replace carriage returns and line feeds before logging so rejected diagnostics remain one redacted line.
  • Fall back to a stable diagnostic when a rejected value throws during text conversion.
  • Cover Error, non-Error, multiline, and throwing-coercion rejections with deterministic logger configuration.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification: This restores generic top-level rejection handling. It adds no command, option, configuration, workflow, remediation, or supported product surface.
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification:
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Proportional security review: PASS at exact head e26a050dbdccdb88b9c55c91f380ac2ceec66c66 against base 4f76eea5c3bde2bc35a5c748232025a618aa4d27; no findings across all nine categories. The effective patch remains limited to the launcher and its package-contract regression test. The existing redacting logger remains authoritative, CR and LF are normalized before output, conversion failures use a stable default message, and the package-contract canary verifies credential redaction without stack or path disclosure. Current-main changes do not alter this launcher boundary. No injection, dependency, endpoint-authentication, cryptography, permission, secret-handling, network, or resource-control regression was introduced.

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: no-docs-needed
  • Evidence: Independently reviewed the exact two-file effective diff at head e26a050dbdccdb88b9c55c91f380ac2ceec66c66 against base 4f76eea5c3bde2bc35a5c748232025a618aa4d27. The change corrects generic top-level failure presentation without changing a documented command, workflow, configuration, recovery action, or supported behavior contract. No docs/ or Fern files changed. Focused package-contract tests passed 4/4 through all three mainline refreshes, git diff --check passed, and normal pre-push CLI TypeScript and version-sync hooks passed. Changed code commentary is concise, and test titles are behavior-oriented with the #8202 reference in the final suffix.
  • Agent: Codex Desktop

DGX Station Hardware Evidence

  • Tested on DGX Station
  • Tested commit: Not applicable.
  • Station profile/scenario: Not applicable.
  • Result: Not applicable.
  • Supporting evidence: Not applicable.

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub — GitHub reports no unverified commit at exact head e26a050dbdccdb88b9c55c91f380ac2ceec66c66.
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run validate:pr passed after refreshing origin/main when hooks were skipped or unavailable — each refresh merge passed commitlint and the source-age check; the published head passed normal pre-push CLI TypeScript and version-sync checks. The earlier exact-head fallback validation, plugin build, and CLI build passed before the mainline-only refreshes.
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — the focused package-contract test passed 4/4 after each of the three mainline refreshes; git diff --check passed and the effective patch remains the intended two-file change.
  • Applicable broad gate passed — exact-head GitHub CI and E2E are running; no result is accepted or waived before completion.
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: San Dang sdang@nvidia.com

Summary by CodeRabbit

  • Bug Fixes

    • Improved CLI startup error handling.
    • Startup failures now display concise, consistent error messages and exit with a failure status.
    • Error output omits internal stack traces and sensitive credential information.
  • Tests

    • Added coverage for startup failures, including non-standard errors, formatting, and safe fallback handling.

Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99 sandl99 self-assigned this Aug 4, 2026
@sandl99 sandl99 mentioned this pull request Aug 4, 2026
23 tasks
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The CLI now handles rejected mainPromise startup calls by logging normalized errors and setting process.exitCode to 1. A package contract test verifies output formatting, stack-trace suppression, newline replacement, credential redaction, and safe fallback handling.

Changes

CLI error handling

Layer / File(s) Summary
Startup rejection handling and validation
bin/nemoclaw.js, test/package-contract/cli/top-level-error.test.ts
The CLI handles rejected startup promises, normalizes Error and non-Error values, and sets exit status 1. The test verifies clean stderr output, empty stdout, stack-trace suppression, newline replacement, credential redaction, and safe handling of values that cannot be converted to text.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: brandonpelfrey

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: handling top-level CLI command failures.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/8202-top-level-cli-errors

Comment @coderabbitai help to get the list of available commands.

@github-code-quality

github-code-quality Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in commit e26a050 in the fix/8202-top-level-c... branch remains at 96%, unchanged from commit 9b6b8df in the main branch.

TypeScript / code-coverage/cli

The overall coverage in commit e26a050 in the fix/8202-top-level-c... branch remains at 81%, unchanged from commit fdd6828 in the main branch.

Show a code coverage summary of the most impacted files.
File main fdd6828 fix/8202-top-level-c... e26a050 +/-
src/lib/onboard...aging-config.ts 100% 90% -10%
src/lib/onboard...hannel-setup.ts 89% 83% -6%
src/lib/messagi...annel-config.ts 96% 92% -4%
src/lib/onboard...point-record.ts 100% 97% -3%
src/lib/onboard...ox-messaging.ts 91% 89% -2%
src/lib/onboard...est-fixtures.ts 93% 96% +3%
src/lib/onboard...ing-selector.ts 78% 82% +4%
src/lib/platform.ts 84% 89% +5%
src/lib/state/r...ry-messaging.ts 48% 55% +7%
src/lib/messagi...an-authority.ts 0% 100% +100%

Updated August 05, 2026 06:53 UTC

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (3)
bin/nemoclaw.js (1)

14-16: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Verify and enforce the one-line error contract.

error.message and String(error) can contain \r or \n. This code passes both values directly to log.error. Confirm that log.error removes line breaks. If it does not, normalize the message before logging and add a multiline rejection case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/nemoclaw.js` around lines 14 - 16, Verify the line-break handling in the
mainPromise rejection handler and the log.error implementation. If log.error
does not remove carriage returns and newlines, normalize the message derived
from error.message or String(error) before logging so the emitted error remains
one line, and add a rejection test covering multiline error text.
test/package-contract/cli/top-level-error.test.ts (2)

20-25: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover the non-Error rejection path.

The launcher has a separate String(error) branch, but this test injects only new Error("Command failed."). Add a second subprocess case that rejects with a string and verifies status 1 and the expected clean stderr.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/package-contract/cli/top-level-error.test.ts` around lines 20 - 25,
Extend the top-level CLI error tests around the existing subprocess case to
cover a non-Error rejection: inject a string rejection from dispatchCli, then
assert the process exits with status 1 and stderr contains the expected clean
string error output. Keep the existing Error rejection case unchanged.

Source: Path instructions


27-31: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make logger configuration deterministic.

The child process inherits NEMOCLAW_LOG_LEVEL and NEMOCLAW_DEBUG from process.env. The logger documents both variables as configuration inputs. Set them to known values or remove them before spawning so the exact stderr assertion does not depend on the environment running Vitest.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/package-contract/cli/top-level-error.test.ts` around lines 27 - 31,
Update the child-process environment in the top-level error test to explicitly
set or remove NEMOCLAW_LOG_LEVEL and NEMOCLAW_DEBUG alongside
NEMOCLAW_DISABLE_AUTO_DISPATCH. Ensure the spawned logger uses deterministic
configuration so the exact stderr assertion is independent of the Vitest
environment.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@bin/nemoclaw.js`:
- Around line 14-16: Verify the line-break handling in the mainPromise rejection
handler and the log.error implementation. If log.error does not remove carriage
returns and newlines, normalize the message derived from error.message or
String(error) before logging so the emitted error remains one line, and add a
rejection test covering multiline error text.

In `@test/package-contract/cli/top-level-error.test.ts`:
- Around line 20-25: Extend the top-level CLI error tests around the existing
subprocess case to cover a non-Error rejection: inject a string rejection from
dispatchCli, then assert the process exits with status 1 and stderr contains the
expected clean string error output. Keep the existing Error rejection case
unchanged.
- Around line 27-31: Update the child-process environment in the top-level error
test to explicitly set or remove NEMOCLAW_LOG_LEVEL and NEMOCLAW_DEBUG alongside
NEMOCLAW_DISABLE_AUTO_DISPATCH. Ensure the spawned logger uses deterministic
configuration so the exact stderr assertion is independent of the Vitest
environment.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 721e740b-a9e3-4a10-b015-098beb44c3b2

📥 Commits

Reviewing files that changed from the base of the PR and between 3835080 and ae259e8.

📒 Files selected for processing (2)
  • bin/nemoclaw.js
  • test/package-contract/cli/top-level-error.test.ts

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — No blocking findings reported

Advisor assessment: No blocking advisor findings reported
Next action: No advisor follow-up needed.
Findings: 0 blockers · 0 warnings · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Model comparison: normalized findings match; normalized terminology decisions differ; normalized E2E selections match; severity counts match.

Second-opinion terminology and E2E selections are advisory. They do not change the primary assessment or E2E / PR Gate.

1 semantic terminology decision

Terminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.

  • justified — throwing coercion at bin/nemoclaw.js:19: Keep “throwing coercion”; it identifies the fallback behavior for conversion failures.

E2E guidance

Advisory only. E2E / PR Gate selects and runs jobs independently.

Recommended E2E: None

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

@wscurran wscurran added area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression labels Aug 4, 2026
@apurvvkumaria apurvvkumaria self-assigned this Aug 4, 2026

@cjagwani cjagwani left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed exact head 50eb4425126c047115acc568b5d83f3528682aec against the uncaught-exception portion of #8202 and the current logger implementation.

Changes requested: #8202's observable contract is a clean single-line error, but log.error does not remove carriage returns or newlines. Passing error.message or String(error) directly therefore allows a rejected multiline diagnostic to emit multiple lines. Normalize CR/LF (and repeated whitespace as appropriate) at this executable boundary before logging, and add a package-contract case that rejects with multiline text and proves exactly one redacted error line is emitted.

Please also cover the separate non-Error branch and make the child logger configuration deterministic by clearing or fixing NEMOCLAW_LOG_LEVEL and NEMOCLAW_DEBUG. Those findings were independently raised by both automated reviewers and are valid for this small boundary contract.

All ordinary exact-head code checks are otherwise green. The primary advisor failure preserved only the same non-Error coverage warning and did not report another blocker; do not retry it unchanged merely to clear the red receipt.

@cjagwani cjagwani left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed exact head 96b7d247e32beeb3c94409194bc7dbfe6b3e268a. The executable boundary now normalizes CR/LF before logging, and the package-contract helper fixes the child logger environment while covering Error, non-Error, multiline, redaction, one-line stderr, exit status, and absence of a Node stack. This closes the requested contract gaps. Exact-head CI and automated review remain required.

@github-actions github-actions Bot added v0.0.103 Release target and removed v0.0.102 labels Aug 4, 2026
cv and others added 4 commits August 4, 2026 16:43
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
@apurvvkumaria

Copy link
Copy Markdown
Collaborator

The advisor warning about rejected values with throwing conversion hooks is addressed in commit 0eb8e4fea. The top-level handler now keeps a stable Command failed. fallback if message extraction or text conversion throws, while preserving the existing one-line redacted diagnostic and status 1. The new package-contract regression uses a rejected object whose Symbol.toPrimitive throws and verifies status 1, one fallback stderr line, and no Node.js stack. The focused suite passed 4/4, normal commit and push hooks passed, and the required documentation review found no user-facing documentation change necessary.

@apurvvkumaria
apurvvkumaria enabled auto-merge (squash) August 5, 2026 05:38
cv added 4 commits August 4, 2026 23:15
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@apurvvkumaria
apurvvkumaria merged commit 5715a4c into main Aug 5, 2026
75 checks passed
@apurvvkumaria
apurvvkumaria deleted the fix/8202-top-level-cli-errors branch August 5, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression v0.0.103 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants