[GH-ISSUE #5531] [Bug] Invalid output-flag values emit TOON despite selecting JSON or JSONL #3367

Closed
opened 2026-10-31 00:39:37 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @coygeek on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5531

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

CLI

Observed behavior

With captured stdout, capabilities --json --token-limit not-a-number exits 1 but prints a two-line TOON diagnostic rather than JSON. An earlier --format json or --format jsonl also loses its selected representation when the token limit is malformed. The diagnostic text survives; JSON/JSONL consumers cannot decode it.

An independent verifier reproduced five malformed-value variants twice each. Every invocation exited 1 with empty stderr. No output filter, target, database, analysis provider, or external service was involved.

Reproduction

Use the built source checkout at the revision below and its pinned Node.js. The independently executed commands used an absolute scripts/rea.mjs entrypoint, a disposable working directory, isolated HOME/XDG/TMPDIR directories, and captured stdout/stderr. $REA_ENTRYPOINT below stands for that entrypoint; no private path is included.

node "$REA_ENTRYPOINT" capabilities --json --token-limit not-a-number
node "$REA_ENTRYPOINT" capabilities --json --token-offset nope
node "$REA_ENTRYPOINT" capabilities --format json --token-limit not-a-number
node "$REA_ENTRYPOINT" capabilities --format jsonl --token-limit not-a-number
node "$REA_ENTRYPOINT" capabilities --json --format bogus

Capture stdout rather than attaching it to a terminal. Each of these exact argument combinations was run twice, including once through the verifier's full reproduction block. JSON decoding failed for all five outputs; the JSONL case produced two non-JSON lines.

Independently executed controls, also run twice:

node "$REA_ENTRYPOINT" capabilities --json --format
node "$REA_ENTRYPOINT" capabilities --json --token-limit 5

Both controls exit 1 with empty stderr and valid JSON: respectively MISSING_OUTPUT_VALUE and UNSUPPORTED_OUTPUT_COMBINATION.

Expected behavior

Preserve the selected JSON or JSONL representation when rejecting a malformed output-flag value. Retain exit status 1 and an explanation identifying the invalid value. No particular error code or envelope is required.

docs/cli.md:437-443 at the tested revision recommends --json for JSON consumers and documents output-flag syntax and structured missing-value failures; lines 455-458 describe structured failure diagnostics. The independently executed capabilities --help advertises JSON/JSONL formats. The missing-value control establishes that argument-validation failures can already preserve JSON serialization.

Impact and scope

P2: a bounded behavioral failure for automated JSON/JSONL consumers receiving malformed output-flag values. Exit status and the textual explanation remain available. A caller can read the retained diagnostic, correct the malformed value, and retry, but must handle non-JSON output on these failures.

Observed scope is the five captured-output variants above. TTY behavior and broader command/platform coverage were not tested. A separate YAML probe returned the same text, which the checkout's YAML parser decoded successfully; no YAML decoding failure is claimed. No successful analysis, target modification, data loss, or security boundary failure was demonstrated.

REA version

6.7.0; source commit 074768901f3cdc8205b61773fb1faf6f6c7b3ca8, using the existing built runtime and lockfile-pinned Incur 0.6.1.

Runtime and platform

Node.js v24.18.0 (repository pin); macOS 27.0.1 arm64. No Hopper or Ghidra provider was used.

Target and artifact context

Not applicable: target-free CLI argument parsing, with stdout/stderr captured in isolated disposable storage.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

Exact stdout for the malformed token-limit cases, including both explicit format selectors:

code: UNKNOWN
message: "Invalid value for --token-limit: \"not-a-number\""

The offset case has the corresponding --token-offset/nope diagnostic. The invalid-format case returns the same two-line representation with a message naming bogus and the accepted formats. All preserve status 1 and empty stderr, while failing the selected JSON/JSONL representation.

The JSON controls retain ok: false with the respective codes above. Existing tests/boundary/cli/cliOutput.test.ts:258-277,290-309 asserts JSON diagnostics for missing values and unsupported structured token windows; those tests were inspected, not run as part of this report.

Typed outcome or recovery expected

A decodable JSON diagnostic, or valid JSONL framing for the explicit JSONL selector, identifying the malformed value. Keep malformed-value rejection, the missing-value control, and the valid-number structured-token-window refusal intact. Do not restore parseability by accepting malformed values or dropping the explanation.

Analysis or suspected cause

Source-derived: scripts/rea.mjs:88-133 passes malformed output values to CLI parsing. src/cliOutput.ts:105-140,168-174 records parseError and defers rejection; src/cli/cliResultOutput.ts:118-124 declines result interception for that state. Incur 0.6.1's dist/Cli.js:1957-1968,1993-2005 throws while extracting the malformed built-in flag, and its catch at lines 308-319 prints hard-coded TOON for captured stdout before command dispatch and format selection.

Additional context

Prepared with AI assistance and independently reproduced through the public CLI before submission.

Related #5448 concerns command-result diagnostics removed by --filter-output. This report uses no filter, retains the explanation, and fails earlier during built-in argument parsing. Upstream's subsequent filtering fix changes result projection but leaves this parse-error guard and argument parser unchanged.

Before submission, upstream main was fetched at c374c2fe7290b914d73d9e27af38b498753ec593. Source comparison found no later change to scripts/rea.mjs, src/cliOutput.ts, the parse-error interception guard, or the pinned Incur dependency. No new runtime reproduction on that later revision is claimed. Searches covered open and closed issues and PRs, including output-flag names, malformed-value symptoms, and the source module. Historical PRs #777, #981, #3811, and #4823 concern different output-validation or flag-normalization cases already present in the tested baseline.

Originally created by @coygeek on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5531 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area CLI ### Observed behavior With captured stdout, `capabilities --json --token-limit not-a-number` exits 1 but prints a two-line TOON diagnostic rather than JSON. An earlier `--format json` or `--format jsonl` also loses its selected representation when the token limit is malformed. The diagnostic text survives; JSON/JSONL consumers cannot decode it. An independent verifier reproduced five malformed-value variants twice each. Every invocation exited 1 with empty stderr. No output filter, target, database, analysis provider, or external service was involved. ### Reproduction Use the built source checkout at the revision below and its pinned Node.js. The independently executed commands used an absolute `scripts/rea.mjs` entrypoint, a disposable working directory, isolated HOME/XDG/TMPDIR directories, and captured stdout/stderr. `$REA_ENTRYPOINT` below stands for that entrypoint; no private path is included. ```sh node "$REA_ENTRYPOINT" capabilities --json --token-limit not-a-number node "$REA_ENTRYPOINT" capabilities --json --token-offset nope node "$REA_ENTRYPOINT" capabilities --format json --token-limit not-a-number node "$REA_ENTRYPOINT" capabilities --format jsonl --token-limit not-a-number node "$REA_ENTRYPOINT" capabilities --json --format bogus ``` Capture stdout rather than attaching it to a terminal. Each of these exact argument combinations was run twice, including once through the verifier's full reproduction block. JSON decoding failed for all five outputs; the JSONL case produced two non-JSON lines. Independently executed controls, also run twice: ```sh node "$REA_ENTRYPOINT" capabilities --json --format node "$REA_ENTRYPOINT" capabilities --json --token-limit 5 ``` Both controls exit 1 with empty stderr and valid JSON: respectively `MISSING_OUTPUT_VALUE` and `UNSUPPORTED_OUTPUT_COMBINATION`. ### Expected behavior Preserve the selected JSON or JSONL representation when rejecting a malformed output-flag value. Retain exit status 1 and an explanation identifying the invalid value. No particular error code or envelope is required. `docs/cli.md:437-443` at the tested revision recommends `--json` for JSON consumers and documents output-flag syntax and structured missing-value failures; lines 455-458 describe structured failure diagnostics. The independently executed `capabilities --help` advertises JSON/JSONL formats. The missing-value control establishes that argument-validation failures can already preserve JSON serialization. ### Impact and scope P2: a bounded behavioral failure for automated JSON/JSONL consumers receiving malformed output-flag values. Exit status and the textual explanation remain available. A caller can read the retained diagnostic, correct the malformed value, and retry, but must handle non-JSON output on these failures. Observed scope is the five captured-output variants above. TTY behavior and broader command/platform coverage were not tested. A separate YAML probe returned the same text, which the checkout's YAML parser decoded successfully; no YAML decoding failure is claimed. No successful analysis, target modification, data loss, or security boundary failure was demonstrated. ### REA version 6.7.0; source commit `074768901f3cdc8205b61773fb1faf6f6c7b3ca8`, using the existing built runtime and lockfile-pinned Incur 0.6.1. ### Runtime and platform Node.js v24.18.0 (repository pin); macOS 27.0.1 arm64. No Hopper or Ghidra provider was used. ### Target and artifact context Not applicable: target-free CLI argument parsing, with stdout/stderr captured in isolated disposable storage. ### Interface CLI ### Earliest failure stage Request parsing or validation ### Relevant output or evidence Exact stdout for the malformed token-limit cases, including both explicit format selectors: ```text code: UNKNOWN message: "Invalid value for --token-limit: \"not-a-number\"" ``` The offset case has the corresponding `--token-offset`/`nope` diagnostic. The invalid-format case returns the same two-line representation with a message naming `bogus` and the accepted formats. All preserve status 1 and empty stderr, while failing the selected JSON/JSONL representation. The JSON controls retain `ok: false` with the respective codes above. Existing `tests/boundary/cli/cliOutput.test.ts:258-277,290-309` asserts JSON diagnostics for missing values and unsupported structured token windows; those tests were inspected, not run as part of this report. ### Typed outcome or recovery expected A decodable JSON diagnostic, or valid JSONL framing for the explicit JSONL selector, identifying the malformed value. Keep malformed-value rejection, the missing-value control, and the valid-number structured-token-window refusal intact. Do not restore parseability by accepting malformed values or dropping the explanation. ### Analysis or suspected cause Source-derived: `scripts/rea.mjs:88-133` passes malformed output values to CLI parsing. `src/cliOutput.ts:105-140,168-174` records `parseError` and defers rejection; `src/cli/cliResultOutput.ts:118-124` declines result interception for that state. Incur 0.6.1's `dist/Cli.js:1957-1968,1993-2005` throws while extracting the malformed built-in flag, and its catch at lines 308-319 prints hard-coded TOON for captured stdout before command dispatch and format selection. ### Additional context Prepared with AI assistance and independently reproduced through the public CLI before submission. Related #5448 concerns command-result diagnostics removed by `--filter-output`. This report uses no filter, retains the explanation, and fails earlier during built-in argument parsing. Upstream's subsequent filtering fix changes result projection but leaves this parse-error guard and argument parser unchanged. Before submission, upstream main was fetched at `c374c2fe7290b914d73d9e27af38b498753ec593`. Source comparison found no later change to `scripts/rea.mjs`, `src/cliOutput.ts`, the parse-error interception guard, or the pinned Incur dependency. No new runtime reproduction on that later revision is claimed. Searches covered open and closed issues and PRs, including output-flag names, malformed-value symptoms, and the source module. Historical PRs #777, #981, #3811, and #4823 concern different output-validation or flag-normalization cases already present in the tested baseline.
Author
Owner

@matbrgz commented on GitHub (Oct 20, 2026):

Cross-referencing with canonical issue #5110 and siblings #5448, #5525, #5530, and #5532 regarding CLI output formatting and error envelope preservation. Cataloged under Cluster AQ in consolidation tracker #4330.

<!-- gh-comment-id:6293047651 --> @matbrgz commented on GitHub (Oct 20, 2026): Cross-referencing with canonical issue #5110 and siblings #5448, #5525, #5530, and #5532 regarding CLI output formatting and error envelope preservation. Cataloged under Cluster AQ in consolidation tracker #4330.
Author
Owner

@CassieFox23 commented on GitHub (Oct 20, 2026):

TL;DR: This still happens on main on Linux. A bad output-flag value prints TOON text even with --json.

Checked on main b3aadaf47 (Node 24.18.0). capabilities --json --token-limit not-a-number exits 1 and prints plain TOON text (code: UNKNOWN, message: ...), not JSON. Stderr is empty. --token-offset nope, --format jsonl --token-limit not-a-number and --json --format bogus do the same.

Not run

  • --format json variant, --token-limit 5 control, repeat runs.

Thanks, coygeek, for the clear report.

Commands

Each run once, exit 1, stderr 0 bytes, stdout captured:

node scripts/rea.mjs capabilities --json --token-limit not-a-number
# code: UNKNOWN
# message: "Invalid value for --token-limit: \"not-a-number\""
node scripts/rea.mjs capabilities --json --format bogus
# code: UNKNOWN
# message: "Invalid format: \"bogus\". Expected one of: toon, json, yaml, md, jsonl"
node scripts/rea.mjs capabilities --json --format
# {"ok":false,"error":{"code":"MISSING_OUTPUT_VALUE", ...}}   (JSON, as in the issue)
Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.11
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 24.18.0
  • Head: b3aadaf47
  • Other: another job shared the box during the run

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

<!-- gh-comment-id:6298147678 --> @CassieFox23 commented on GitHub (Oct 20, 2026): **TL;DR:** This still happens on main on Linux. A bad output-flag value prints TOON text even with `--json`. Checked on main b3aadaf47 (Node 24.18.0). `capabilities --json --token-limit not-a-number` exits 1 and prints plain TOON text (`code: UNKNOWN`, `message: ...`), not JSON. Stderr is empty. `--token-offset nope`, `--format jsonl --token-limit not-a-number` and `--json --format bogus` do the same. ### Not run - `--format json` variant, `--token-limit 5` control, repeat runs. Thanks, coygeek, for the clear report. <details> <summary>Commands</summary> Each run once, exit 1, stderr 0 bytes, stdout captured: ```sh node scripts/rea.mjs capabilities --json --token-limit not-a-number # code: UNKNOWN # message: "Invalid value for --token-limit: \"not-a-number\"" node scripts/rea.mjs capabilities --json --format bogus # code: UNKNOWN # message: "Invalid format: \"bogus\". Expected one of: toon, json, yaml, md, jsonl" node scripts/rea.mjs capabilities --json --format # {"ok":false,"error":{"code":"MISSING_OUTPUT_VALUE", ...}} (JSON, as in the issue) ``` </details> <details> <summary>Test setup</summary> - Box: Nobara 44 (Fedora 44 base), Linux 7.2.11 - CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads - RAM: 32 GB DDR4-3600 - Node: 24.18.0 - Head: b3aadaf47 - Other: another job shared the box during the run </details> 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
Author
Owner

@coygeek commented on GitHub (Oct 24, 2026):

Checked the reported fix on main at d87e73f2db.

Invalid valued flags are accumulated while effective valid format selection is retained; error validation chooses json/jsonl (or yaml), never TOON. A production-source probe tested the five original invalid-value selectors including invalid format after --json. Public compiled CLI tests assert decodable INVALID_OUTPUT_VALUE and include the original --json token-limit invocation.

Implementation: cliOutput.ts, cliOutput.ts.

The relevant regression checks in cliOutput.test.ts passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.

<!-- gh-comment-id:6380738495 --> @coygeek commented on GitHub (Oct 24, 2026): Checked the reported fix on `main` at d87e73f2db50be72d33a4b3c7199af35518b441c. Invalid valued flags are accumulated while effective valid format selection is retained; error validation chooses json/jsonl (or yaml), never TOON. A production-source probe tested the five original invalid-value selectors including invalid format after --json. Public compiled CLI tests assert decodable INVALID_OUTPUT_VALUE and include the original --json token-limit invocation. Implementation: [cliOutput.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/cliOutput.ts#L178), [cliOutput.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/cliOutput.ts#L245). The relevant regression checks in [cliOutput.test.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/tests/boundary/cli/cliOutput.test.ts) passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3367
No description provided.