Skip to content

fix(cli): report oclif parse errors without a raw stack trace - #8125

Merged
cv merged 1 commit into
mainfrom
fix/oclif-parse-error-boundary
Aug 4, 2026
Merged

fix(cli): report oclif parse errors without a raw stack trace#8125
cv merged 1 commit into
mainfrom
fix/oclif-parse-error-boundary

Conversation

@laitingsheng

@laitingsheng laitingsheng commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Passing a value outside a flag's or argument's declared enum crashed the CLI instead of reporting the mistake. oclif's parse error escaped as an unhandled rejection, so the user got a Node stack trace, an error-property dump, and the Node version banner, and the process exited 1 instead of the declared parser code 2. The actionable line was present but buried mid-trace. Those commands now print that line on its own and exit 2.

Related Issue

Fixes #8123

Changes

  • src/lib/cli/oclif-runner.ts: runOclifCommandById maps oclif errors to exit codes by hand rather than delegating to oclif's handle(), and it recognized parse errors from a list of class names. That list covered four of oclif's seven CLIParseError subclasses, so FlagInvalidOptionError and ArgInvalidOptionError fell through to the final rethrow and out of dispatchCli(), which has no rejection handler. Added hasOclifParseErrorShape, which matches on the three markers the CLIParseError base class gives every subclass: a numeric oclif.exit, an own parse property, and a boolean showHelp. Matching the shape rather than the name covers the subclasses added since the list was written and any added later.
  • src/lib/cli/oclif-runner.ts: the existing name list stays as written and is OR'd with the new check, so no error that already reached the parse branch changes route. Recognized errors keep using the existing exit(exitCode ?? 1) line, which yields 2 for a parse error with no further change.
  • Only the direct command-id route was affected. The native internal and sandbox namespaces go through runOclifArgv, which does call oclif's handle() and already printed these cleanly, which is why nemoclaw <sandbox-name> inference set behaved while the global nemoclaw inference set crashed.
  • Tests: src/lib/cli/oclif-runner.test.ts covers an invalid enum flag value, an invalid enum argument value, a parse error whose class name is unknown but whose shape matches, and a command failure carrying an unrelated parse property that must still rethrow. test/cli/oclif-parse-errors.test.ts runs the real CLI for both user-visible commands and asserts the exit code, the actionable line, and the absence of stack frames, @oclif/core paths, and the Node version banner.

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: no documented behavior changes. docs/inference/configure-model-capabilities.mdx documents which --reasoning-effort values are accepted, and docs/reference/commands.mdx lists the commands and flags. No page documents the previous exit code, the stack trace, or the error text for a rejected value.
  • 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:

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: blocked
  • Evidence: no documentation paths changed. The subagent review did not run because the authoring session is configured not to spawn subagents without an explicit request. The documentation assessment recorded under Quality Gates was made directly against the two pages that mention the affected commands and flag values.
  • Agent: Claude Code

DGX Station Hardware Evidence

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

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • 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
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result or justification: npx vitest run --project cli src/lib/cli/ --project integration test/cli/dispatch-basics.test.ts test/cli/onboard-compatibility.test.ts test/cli/oclif-parse-errors.test.ts — 13 files, 136 tests passed. With src/lib/cli/oclif-runner.ts reverted and dist rebuilt, the 5 new assertions fail and the other 15 in those two files still pass, which pins both the recognition change and the exit code. Before the fix, nemoclaw inference set --reasoning-effort ultra and nemoclaw completion powershell reproduced the reported trace and exit 1; after it, both print one line plus the help hint and exit 2, while nemoclaw onboard --non-interactiv is unchanged. npm run typecheck:cli clean.
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result:
  • 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: Tinson Lai tinsonl@nvidia.com

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of invalid command-line flag and argument values.
    • Parse errors now consistently display clear validation messages and exit with code 2.
    • Prevented stack traces and internal parser details from appearing in user-facing error output.
    • Unrelated command failures continue to propagate normally without being incorrectly formatted as parse errors.
  • Tests

    • Added coverage for invalid enum values and structurally recognized parser errors.

The direct command-id route recognized parse errors by class name, so an
invalid enum flag or argument value escaped as an unhandled rejection: a Node
stack trace, an error-property dump, and exit 1 instead of the declared 2.
Recognize the shape every oclif parse error carries so the route prints one
actionable line and exits with the parser code.

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The CLI now recognizes oclif parse errors by structural properties. Tests cover invalid enum flags and arguments, formatted exit code 2 responses, removal of parser details, and rethrowing unrelated command failures.

Changes

CLI parse error handling

Layer / File(s) Summary
Structural parse error detection
src/lib/cli/oclif-runner.ts, src/lib/cli/oclif-runner.test.ts
isOclifParseError now recognizes errors with oclif exit metadata, an own parse property, and boolean showHelp metadata. Tests cover matching unknown parser error classes and rejecting unrelated failures.
Parse error output validation
src/lib/cli/oclif-runner.test.ts, test/cli/oclif-parse-errors.test.ts
Tests cover invalid enum flags and arguments, exit code 2, validation messages, and output without stack traces or internal parser details.

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

Suggested labels: area: cli

Suggested reviewers: brandonpelfrey

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: clean handling of oclif parse errors without raw stack traces.
Linked Issues check ✅ Passed The implementation and tests address issue #8123 by formatting invalid enum errors, preserving exit code 2, and preventing stack traces.
Out of Scope Changes check ✅ Passed All changes support the linked issue by updating parse-error detection and adding focused CLI and unit tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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/oclif-parse-error-boundary

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

@github-code-quality

github-code-quality Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in commit de827bf in the fix/oclif-parse-erro... branch remains at 96%, unchanged from commit 4cd4d64 in the main branch.

TypeScript / code-coverage/cli

The overall coverage in commit de827bf in the fix/oclif-parse-erro... branch remains at 81%, unchanged from commit a931be4 in the main branch.


Updated August 03, 2026 11:15 UTC

@laitingsheng laitingsheng added NV QA Bugs found by the NVIDIA QA Team area: cli Command line interface, flags, terminal UX, or output area: inference Inference routing, serving, model selection, or outputs bug-fix PR fixes a bug or regression and removed NV QA Bugs found by the NVIDIA QA Team labels Aug 3, 2026

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@test/cli/oclif-parse-errors.test.ts`:
- Around line 22-26: Update both CLI parse-error tests around the
reasoning-effort validation assertions to explicitly verify the required help
hint is present in r.out, in addition to the validation message and clean
parse-failure checks. Use the observable command output and preserve the
existing exit-code assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 307e3f6c-8242-4cfb-97c4-975d4c4b9abd

📥 Commits

Reviewing files that changed from the base of the PR and between 4cd4d64 and de827bf.

📒 Files selected for processing (3)
  • src/lib/cli/oclif-runner.test.ts
  • src/lib/cli/oclif-runner.ts
  • test/cli/oclif-parse-errors.test.ts

Comment on lines +22 to +26
expect(r.code).toBe(PARSER_EXIT_CODE);
expect(r.out).toContain(
"Expected --reasoning-effort=ultra to be one of: low, medium, high, default",
);
expectCleanParseFailure(r.out);

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the help hint in both CLI tests.

Issue #8123 requires the validation message and the help hint. These assertions pass if output omits the help hint.

Proposed test change
     expect(r.out).toContain(
       "Expected --reasoning-effort=ultra to be one of: low, medium, high, default",
     );
+    expect(r.out).toContain("See more help with --help");
     expectCleanParseFailure(r.out);
@@
     expect(r.code).toBe(PARSER_EXIT_CODE);
     expect(r.out).toContain("Expected powershell to be one of: bash, zsh, fish");
+    expect(r.out).toContain("See more help with --help");
     expectCleanParseFailure(r.out);

As per path instructions, “Prefer observable outcomes through the public boundary.”

Also applies to: 32-34

🤖 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/cli/oclif-parse-errors.test.ts` around lines 22 - 26, Update both CLI
parse-error tests around the reasoning-effort validation assertions to
explicitly verify the required help hint is present in r.out, in addition to the
validation message and clean parse-failure checks. Use the observable command
output and preserve the existing exit-code assertions.

Source: Path instructions

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Informational

Advisor assessment: Informational / low confidence
Next action: No advisor follow-up needed.
Findings: 0 blockers · 0 warnings · 0 suggestions
Status: Partial review preserved 0 canonical finding(s) and 1 terminology decision(s) before the advisor stopped.

Model lanes

  • GPT-5.6 Terra (primary): Failed after a partial review · low confidence · 0 blockers · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions

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.

  • established — stack trace at test/cli/oclif-parse-errors.test.ts:17: Keep `stack trace`; repository tests, comments, and writing guidance use it for this user-visible output.

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.

@prekshivyas prekshivyas self-assigned this Aug 3, 2026

@apurvvkumaria apurvvkumaria 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 de827bf. The structural oclif parse-error predicate is narrowly gated by exit metadata, an own parse field, and boolean help metadata, with unit and CLI regression coverage plus a negative command-failure case. I found no blocking defect. The failing installer test is in unrelated station-pair preparation coverage, while the affected CLI suites passed; automated advisor output reports no blocker.

@cv
cv merged commit 6a838ff into main Aug 4, 2026
73 of 79 checks passed
@cv
cv deleted the fix/oclif-parse-error-boundary branch August 4, 2026 01:19
apurvvkumaria added a commit that referenced this pull request Aug 4, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Prepares the canonical v0.0.102 release documentation from the current
release-labeled scope.
The change adds a dated changelog for all 38 user-facing shipping PRs
and corrects the OpenClaw agent command reference for the behavior
delivered by #8191.

## Changes

- Add `docs/changelog/2026-08-04.mdx` with the v0.0.102 release summary,
detailed behavior changes, support boundaries, security evidence links,
and links to durable documentation.
- Update `docs/reference/commands.mdx` to describe non-JSON OpenClaw
output capture, its combined limit, marker handling, stream suppression,
recovery guidance, and exit behavior.
- [#8167](#8167) ->
`docs/changelog/2026-08-04.mdx`: Records authenticated attachment of
operator-managed llama.cpp servers.
- [#8129](#8129) ->
`docs/changelog/2026-08-04.mdx`: Records the Experimental managed vLLM
profile for two DGX Spark systems.
- [#7983](#7983) ->
`docs/changelog/2026-08-04.mdx`: Records qualification of the May 2026
GB300WS factory image.
- [#8207](#8207) ->
`docs/changelog/2026-08-04.mdx`: Records the qualified DGX Station
driver transaction.
- [#8208](#8208) ->
`docs/changelog/2026-08-04.mdx`: Records mode-bound Express resume
state.
- [#8158](#8158) ->
`docs/changelog/2026-08-04.mdx`: Records recovery of host-global
dual-Station runtime ownership.
- [#8145](#8145) ->
`docs/changelog/2026-08-04.mdx`: Records Windows-host Ollama validation
from Docker Desktop's network context.
- [#8190](#8190) ->
`docs/changelog/2026-08-04.mdx`: Records HTTP model pulls when WSL has
no local Ollama executable.
- [#8195](#8195) ->
`docs/changelog/2026-08-04.mdx`: Records reuse of a healthy
installer-managed CLI.
- [#8053](#8053) ->
`docs/changelog/2026-08-04.mdx`: Records early rejection of incompatible
OpenShell gateway versions.
- [#8098](#8098) ->
`docs/changelog/2026-08-04.mdx`: Records the bounded
package-service-to-standalone gateway recovery transition.
- [#8216](#8216) ->
`docs/changelog/2026-08-04.mdx`: Records the final dashboard port
selected during multi-sandbox onboarding.
- [#8146](#8146) ->
`docs/changelog/2026-08-04.mdx`: Records managed startup-state
restoration for stopped sandboxes.
- [#8092](#8092) ->
`docs/changelog/2026-08-04.mdx`: Records gateway watchdog recovery for
classified not-serving states.
- [#8182](#8182) ->
`docs/changelog/2026-08-04.mdx`: Records consistent managed-recovery
wait configuration.
- [#8040](#8040) ->
`docs/changelog/2026-08-04.mdx`: Records Docker sandbox rollback
authority through late validation.
- [#8130](#8130) ->
`docs/changelog/2026-08-04.mdx`: Records bounded Shields deadline
recovery and durable containment.
- [#8086](#8086) ->
`docs/changelog/2026-08-04.mdx`: Records repair of narrowly validated
permission-only configuration drift.
- [#8122](#8122) ->
`docs/changelog/2026-08-04.mdx`: Records prompt failure and guidance for
corrupt transition locks.
- [#8124](#8124) ->
`docs/changelog/2026-08-04.mdx`: Records policy restoration flags,
previews, and target revalidation.
- [#7886](#7886) ->
`docs/changelog/2026-08-04.mdx`: Records explicit destruction after
pre-delete Shields hardening failures while preserving recovery
authority.
- [#7901](#7901) ->
`docs/changelog/2026-08-04.mdx`: Records multi-port uninstall behavior
and shared-resource preservation.
- [#7984](#7984) ->
`docs/changelog/2026-08-04.mdx`: Records one classified transient remote
MCP startup retry.
- [#7954](#7954) ->
`docs/changelog/2026-08-04.mdx`: Records bounded hosted-inference probe
replies.
- [#7574](#7574) ->
`docs/changelog/2026-08-04.mdx`: Records preservation of validated
reasoning capabilities through onboarding.
- [#8089](#8089) ->
`docs/changelog/2026-08-04.mdx`: Records proxy routing for Hermes
WhatsApp pairing and media traffic.
- [#7682](#7682) ->
`docs/changelog/2026-08-04.mdx`: Records native Hermes session deletion
and identifier validation.
- [#8150](#8150) ->
`docs/changelog/2026-08-04.mdx`: Records corporate CA trust for
LangChain Deep Agents Code image builds.
- [#8156](#8156) ->
`docs/changelog/2026-08-04.mdx`: Records reviewed managed runtime
dependency remediation.
- [#8180](#8180) ->
`docs/changelog/2026-08-04.mdx`: Records reviewed MCP discovery runtime
dependency updates.
- [#8196](#8196) ->
`docs/changelog/2026-08-04.mdx`: Records private npm dependency
remediation across managed images.
- [#8203](#8203) ->
`docs/changelog/2026-08-04.mdx`: Records reviewed Hermes and LangChain
Deep Agents Code Python dependency updates.
- [#8125](#8125) ->
`docs/changelog/2026-08-04.mdx`: Records bounded diagnostics for invalid
enumerated CLI values.
- [#8193](#8193) ->
`docs/changelog/2026-08-04.mdx`: Records bounded diagnostics for
unresolved sandbox base images.
- [#8118](#8118) ->
`docs/changelog/2026-08-04.mdx`: Records bounded diagnostics for changed
gateway authority.
- [#8191](#8191) ->
`docs/changelog/2026-08-04.mdx`, `docs/reference/commands.mdx`: Records
output capture, marker handling, recovery guidance, and exit behavior
for non-JSON OpenClaw agent commands.
- [#8187](#8187) ->
`docs/changelog/2026-08-04.mdx`: Records the aligned
interactive-installation start across supported agents.
- [#8153](#8153) ->
`docs/changelog/2026-08-04.mdx`: Records current product capabilities
and support boundaries.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [x] 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:
- [x] Tests not applicable — justification: This documentation-only
release preparation does not change executable behavior. Existing
changelog and published-route tests pass.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] 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:

## Documentation Writer Review

- [x] Documentation writer subagent reviewed the completed changes
- Result: `docs-updated`
- Evidence: Independently reviewed `docs/changelog/2026-08-04.mdx` and
`docs/reference/commands.mdx` at commit `b89913780`. All 38 user-facing
v0.0.102 PRs are represented, #8191 behavior matches the implementation,
and the writing rules, documentation style, controlled terminology,
route structure, and skip policy pass review. Targeted tests pass 36/36
and the documentation build completes with 0 errors.
- Agent: Codex Desktop independent documentation writer
<!-- docs-review-head-sha: b899137 -->
<!-- docs-review-agents-blob-sha: 3dd7c24 -->

## 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

- [x] PR description includes a `Signed-off-by:` line and every commit
appears as `Verified` in GitHub
- [x] 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
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — `npx vitest run --project integration
test/changelog-docs.test.ts test/check-docs-published-routes.test.ts`
passed 36/36.
- [x] Applicable broad gate passed — not applicable to
documentation-only changes; `npm run docs` completed successfully with 0
errors.
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only) —
completed with 0 errors and 2 existing Fern warnings.
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [x] New doc pages include SPDX header and frontmatter (new pages only)
— the native dated changelog uses the required parser-safe MDX SPDX
comment and intentionally has no frontmatter.

---
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Documentation**
- Added release notes for v0.0.102, covering authentication, hardware
setup, WSL, installer recovery, sandbox resilience, policy management,
inference reliability, CLI improvements, and unified quickstarts.
- Updated command documentation to explain how non-JSON agent output is
collected, replayed, and reported.

- **Bug Fixes**
- Improved command-output recovery guidance when output exceeds limits
or contains unsupported fallback markers.
- Preserved accurate command exit-status reporting after output
processing.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
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 area: inference Inference routing, serving, model selection, or outputs bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Ubuntu 26.04][CLI&UX] invalid --reasoning-effort value crashes with uncaught oclif FlagInvalidOptionError stack trace instead of clean parse error

4 participants