[GH-ISSUE #2273] [Bug] CLI --full-output wraps analysis failures in {"ok": true} while exiting 1 #753

Closed
opened 2026-10-15 18:27:59 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @BeLit-Development-2 on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2273

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 --full-output, every REA analysis/domain failure is wrapped in a success envelope: {"ok": true, "data": { <error projection> }}. The process still exits 1. Framework-level failures from the same binary correctly produce {"ok": false, "error": {...}}. So the envelope's ok field disagrees with the exit code exactly for the errors that matter most.

Command (all with --format json --full-output) Exit Envelope
rea inspect-managed-artifact C:\definitely\missing\x.dll 1 {"ok":true,"data":{"error":"Analysis failed","code":"target_unavailable",…}}
rea inspect-web-network-capture C:\definitely\missing\x.har har 1 {"ok":true,"data":{"code":"invalid_request",…}}
rea capture-electron-scenario <json with missing executable> 1 {"ok":true,"data":{"error":"Electron analysis failed","code":"invalid_request",…}}
same as row 1 with --format yaml 1 ok: true / data: / error: Analysis failed …
rea inspect-managed-artifact --no-such-flag 1 {"ok":false,"error":{"code":"UNKNOWN","message":"Unknown flag: --no-such-flag"}} ✅
rea inspect-web-network-capture (missing args) 1 {"ok":false,"error":{"code":"VALIDATION_ERROR",…}} ✅
rea no-such-command 1 {"ok":false,"error":{"code":"COMMAND_NOT_FOUND",…}} ✅
rea inspect-managed-artifact <valid .dll> 0 {"ok":true,"data":{…}} ✅

Without --full-output the bare error projection is printed, which is consistent with exit 1. The contradiction appears only in the full envelope.

Reproduction

  1. rea inspect-managed-artifact C:\definitely\missing\x.dll --format json --full-output
  2. Observe exit code 1 and stdout {"ok":true,"data":{"error":"Analysis failed","code":"target_unavailable","category":"unavailable","message":"Cannot open artifact: target does not exist … ENOENT …",…}}
  3. Compare rea inspect-managed-artifact --no-such-flag --format json --full-output: exit 1 and {"ok":false,"error":{…}}.

Expected behavior

When a command fails (non-zero exit), the full envelope is {"ok": false, "error": {…}, "meta": {…}}, with the existing typed error projection (code, category, message, retryable, remediation, details) as the error payload, the same shape the framework already uses for its own failures. ok: true only for successful operations.

Impact and scope

  • Scripts and agents that use --full-output and branch on ok, which is the point of an envelope, treat failed analyses as successes and go on to parse data as a result. The failure is visible only through the exit code or by sniffing data.error / data.code.
  • Affects every domain/analysis failure routed through the CLI command logger. Observed on inspect-managed-artifact, inspect-web-network-capture and capture-electron-scenario, in JSON and YAML.
  • Not affected: exit codes (correct), output without --full-output, and framework-level errors (unknown flag/command, schema validation).

REA version

6.4.0 (npm, global install)

Runtime and platform

Node 24.20.0; Windows 11 x64 (10.0.26300)

Target and artifact context

Not applicable (CLI output envelope)

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

$ rea inspect-managed-artifact C:\definitely\missing\x.dll --format json --full-output   # exit 1
{"ok":true,"data":{"error":"Analysis failed","code":"target_unavailable","category":"unavailable","message":"Cannot open artifact: target does not exist or a path component is not a directory: ENOENT: no such file or directory, access 'C:\\definitely\\missing\\x.dll'. Check that the path exists, is readable, and points to a supported file.","retryable":false,"remediation":{…}}, …}

$ rea inspect-managed-artifact C:\definitely\missing\x.dll --format yaml --full-output    # exit 1
ok: true
data:
  error: Analysis failed
  code: target_unavailable
  …

$ rea inspect-managed-artifact --no-such-flag --format json --full-output                 # exit 1
{"ok":false,"error":{"code":"UNKNOWN","message":"Unknown flag: --no-such-flag"},"meta":{"command":"inspect-managed-artifact","duration":"1ms"}}

Typed outcome or recovery expected

ok: false plus error = the existing analysisCliErrorEnvelope / AnalysisErrorProjection, so ok, the exit code and the presence of error always agree.

Analysis or suspected cause

Source-derived: dist/cliLogging.js, logCliCommand (lines 21–47). When isCliOperationFailure(value) is true, it sets process.exitCode = 1 but returns the value unchanged. When an AnalysisError is thrown, it catches it, sets process.exitCode = 1, and returns projectAnalysisError(cause) as a normal return value. In both paths the CLI framework (incur) receives an ordinary resolved value and renders it as {ok: true, data: value}. The framework's own failures go through its error channel, which is why those render ok: false.

Possible fix: when isCliOperationFailure holds, hand the projection to the framework's error path (throw or the framework's error helper) with the projection as the error body, or post-process the full envelope so failures render as ok: false. The same applies to the healthy === false branch of isCliOperationFailure (e.g. an unhealthy rea doctor), which also exits 1.

Additional context

  • Found during a ground-truth test run of REA 6.4.0 on Windows, while filing #2272.
  • A regression test could assert, for a representative command per failure class (target unavailable, invalid input, capability unavailable), that --full-output yields ok === false, error.code present, data absent, and exit code 1.
Originally created by @BeLit-Development-2 on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2273 ### 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 `--full-output`, every REA analysis/domain failure is wrapped in a **success** envelope: `{"ok": true, "data": { <error projection> }}`. The process still exits 1. Framework-level failures from the same binary correctly produce `{"ok": false, "error": {...}}`. So the envelope's `ok` field disagrees with the exit code exactly for the errors that matter most. | Command (all with `--format json --full-output`) | Exit | Envelope | |---|---|---| | `rea inspect-managed-artifact C:\definitely\missing\x.dll` | 1 | `{"ok":true,"data":{"error":"Analysis failed","code":"target_unavailable",…}}` | | `rea inspect-web-network-capture C:\definitely\missing\x.har har` | 1 | `{"ok":true,"data":{"code":"invalid_request",…}}` | | `rea capture-electron-scenario <json with missing executable>` | 1 | `{"ok":true,"data":{"error":"Electron analysis failed","code":"invalid_request",…}}` | | same as row 1 with `--format yaml` | 1 | `ok: true` / `data:` / ` error: Analysis failed` … | | `rea inspect-managed-artifact --no-such-flag` | 1 | `{"ok":false,"error":{"code":"UNKNOWN","message":"Unknown flag: --no-such-flag"}}` ✅ | | `rea inspect-web-network-capture` (missing args) | 1 | `{"ok":false,"error":{"code":"VALIDATION_ERROR",…}}` ✅ | | `rea no-such-command` | 1 | `{"ok":false,"error":{"code":"COMMAND_NOT_FOUND",…}}` ✅ | | `rea inspect-managed-artifact <valid .dll>` | 0 | `{"ok":true,"data":{…}}` ✅ | Without `--full-output` the bare error projection is printed, which is consistent with exit 1. The contradiction appears only in the full envelope. ### Reproduction 1. `rea inspect-managed-artifact C:\definitely\missing\x.dll --format json --full-output` 2. Observe exit code 1 and stdout `{"ok":true,"data":{"error":"Analysis failed","code":"target_unavailable","category":"unavailable","message":"Cannot open artifact: target does not exist … ENOENT …",…}}` 3. Compare `rea inspect-managed-artifact --no-such-flag --format json --full-output`: exit 1 and `{"ok":false,"error":{…}}`. ### Expected behavior When a command fails (non-zero exit), the full envelope is `{"ok": false, "error": {…}, "meta": {…}}`, with the existing typed error projection (code, category, message, retryable, remediation, details) as the `error` payload, the same shape the framework already uses for its own failures. `ok: true` only for successful operations. ### Impact and scope - Scripts and agents that use `--full-output` and branch on `ok`, which is the point of an envelope, treat failed analyses as successes and go on to parse `data` as a result. The failure is visible only through the exit code or by sniffing `data.error` / `data.code`. - Affects every domain/analysis failure routed through the CLI command logger. Observed on `inspect-managed-artifact`, `inspect-web-network-capture` and `capture-electron-scenario`, in JSON and YAML. - Not affected: exit codes (correct), output without `--full-output`, and framework-level errors (unknown flag/command, schema validation). ### REA version 6.4.0 (npm, global install) ### Runtime and platform Node 24.20.0; Windows 11 x64 (10.0.26300) ### Target and artifact context Not applicable (CLI output envelope) ### Interface CLI ### Earliest failure stage Transport or result projection ### Relevant output or evidence ```text $ rea inspect-managed-artifact C:\definitely\missing\x.dll --format json --full-output # exit 1 {"ok":true,"data":{"error":"Analysis failed","code":"target_unavailable","category":"unavailable","message":"Cannot open artifact: target does not exist or a path component is not a directory: ENOENT: no such file or directory, access 'C:\\definitely\\missing\\x.dll'. Check that the path exists, is readable, and points to a supported file.","retryable":false,"remediation":{…}}, …} $ rea inspect-managed-artifact C:\definitely\missing\x.dll --format yaml --full-output # exit 1 ok: true data: error: Analysis failed code: target_unavailable … $ rea inspect-managed-artifact --no-such-flag --format json --full-output # exit 1 {"ok":false,"error":{"code":"UNKNOWN","message":"Unknown flag: --no-such-flag"},"meta":{"command":"inspect-managed-artifact","duration":"1ms"}} ``` ### Typed outcome or recovery expected `ok: false` plus `error` = the existing `analysisCliErrorEnvelope` / `AnalysisErrorProjection`, so `ok`, the exit code and the presence of `error` always agree. ### Analysis or suspected cause *Source-derived:* `dist/cliLogging.js`, `logCliCommand` (lines 21–47). When `isCliOperationFailure(value)` is true, it sets `process.exitCode = 1` but returns the value unchanged. When an `AnalysisError` is thrown, it catches it, sets `process.exitCode = 1`, and returns `projectAnalysisError(cause)` as a normal return value. In both paths the CLI framework (`incur`) receives an ordinary resolved value and renders it as `{ok: true, data: value}`. The framework's own failures go through its error channel, which is why those render `ok: false`. Possible fix: when `isCliOperationFailure` holds, hand the projection to the framework's error path (throw or the framework's error helper) with the projection as the error body, or post-process the full envelope so failures render as `ok: false`. The same applies to the `healthy === false` branch of `isCliOperationFailure` (e.g. an unhealthy `rea doctor`), which also exits 1. ### Additional context - Found during a ground-truth test run of REA 6.4.0 on Windows, while filing #2272. - A regression test could assert, for a representative command per failure class (target unavailable, invalid input, capability unavailable), that `--full-output` yields `ok === false`, `error.code` present, `data` absent, and exit code 1.
bsakaguchi 2026-10-15 18:27:59 +00:00
Author
Owner

@jeonjw85 commented on GitHub (Oct 12, 2026):

I'll work on this. I'll reproduce the failure through the CLI, then make the full-output envelope report the failed operation while preserving the typed error details and existing non-full output. The reference-source tests currently pin the legacy wrapper, so I'll cover that compatibility case as well as JSON and YAML output.

<!-- gh-comment-id:6129740646 --> @jeonjw85 commented on GitHub (Oct 12, 2026): I'll work on this. I'll reproduce the failure through the CLI, then make the full-output envelope report the failed operation while preserving the typed error details and existing non-full output. The reference-source tests currently pin the legacy wrapper, so I'll cover that compatibility case as well as JSON and YAML output.
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#753
No description provided.