[GH-ISSUE #3210] [Bug] Malformed start-adb-activity extras omit required error classification and recovery fields #1148

Closed
opened 2026-10-15 18:31:31 +00:00 by bsakaguchi · 2 comments
Owner

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

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

rea start-adb-activity rejects a nonempty --extra value with fewer than two colons, but its JSON response contains only code: "UNKNOWN" and a message. It omits the required category, retryable, and remediation fields from the shared error contract.

The values string:key, :, and string each exited 1, wrote the incomplete JSON error to stdout, and wrote no stderr. All three payloads failed validation against the checked-in error schema. The unsupported-type control bogus:key:value exited 1 with a schema-valid invalid_request response. The valid-extra control string:key:value reached provider admission and returned a schema-valid capability_unavailable response for the deliberately missing adb executable.

Reproduction

  1. From a clean checkout at 58300885207133422af235e0f2b10658cf958b03, use the repository's pinned Node.js and npm toolchain and prepare the standalone runtime:

    npm ci
    npm run build:cached
    
  2. Run this from the checkout root in a shell without set -e. It creates an isolated home and selects a nonexistent adb executable. No input files, real adb client, device, or emulator are needed. The first three inputs reproduce missing delimiters; the last two are controls.

    repro_dir="$(mktemp -d)"
    mkdir -p "$repro_dir/home"
    for extra in 'string:key' ':' 'string' 'bogus:key:value' 'string:key:value'; do
      printf 'extra=%s\n' "$extra"
      env HOME="$repro_dir/home" \
        XDG_CONFIG_HOME="$repro_dir/home/config" \
        XDG_CACHE_HOME="$repro_dir/home/cache" \
        XDG_DATA_HOME="$repro_dir/home/data" \
        REA_ADB_PATH="$repro_dir/missing-adb" \
        node scripts/rea.mjs start-adb-activity emulator-5554 \
          android.intent.action.VIEW --extra "$extra" --json
      printf 'exit=%s\n' "$?"
    done
    rm -rf "$repro_dir"
    
  3. Observe that each of the first three commands exits 1 with UNKNOWN and no category, retryability, or remediation. Compare the two controls, which retain canonical error fields.

Verification used the prepared baseline runtime and locked dependencies. The clean-checkout install and build prerequisites above were not rerun during that verification.

Expected behavior

Malformed typed-extra syntax should return code: "invalid_request", category: "invalid_input", a nonempty message, a boolean retryable, and a nonempty remediation.action. The command should exit 1 before attempting a device operation.

docs/error-contract.schema.json requires these fields for the invalid_request variant and does not allow UNKNOWN as an error code. Details are optional for invalid_request. src/contracts/errorSchemas.ts:34 describes the stable schema shared by every CLI and MCP error surface. AGENTS.md, under Architecture and Cleanup, requires parsing unknown boundary values and modeling expected failures with the tagged error algebra and Result. The command's start-adb-activity --help documents repeatable type:key:value extras.

Impact and scope

Callers cannot classify these malformed-input failures or read retryability and recovery through the shared error contract. The reproduced defect is bounded to nonempty extras with fewer than two colons. Input rejection and exit status remain correct, and no device operation was observed for those malformed values. No downstream consumer crash was tested.

Correcting the value to type:key:value is a practical workaround for submitting the intended request. The valid-extra control demonstrated normal provider admission, rather than a successful activity launch. That workaround does not restore canonical failure handling for callers that must process malformed input.

REA version

6.4.0 (main at 5830088520)

Runtime and platform

Node 26.10.0; macOS 27.0 arm64. The Node version was measured. The OS and architecture are supplied platform context and were not independently established during verification.

Target and artifact context

CLI typed-extra parsing with serial emulator-5554 and action android.intent.action.VIEW. The serial is a placeholder; no device or emulator was contacted. Each process used isolated HOME and XDG directories and an intentionally nonexistent REA_ADB_PATH. No binary or artifact input is required.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

extra=string:key
{"code":"UNKNOWN","message":"--extra expects type:key:value, received: string:key"}
exit=1

extra=bogus:key:value
{"code":"invalid_request","category":"invalid_input","message":"Analysis input is invalid. Check the arguments and try again.","retryable":true,"remediation":{"action":"Correct the listed arguments and retry."}}
exit=1

Typed outcome or recovery expected

Return a schema-valid invalid_request projection with category invalid_input, boolean retryability, and a nonempty remediation.action for each malformed delimiter case, while preserving exit 1 and rejection before provider execution. Keep canonical rejection for the unsupported-type control. Keep valid-extra parsing reaching provider admission and reporting the intentionally missing adb executable as capability_unavailable. These controls distinguish restored classification from blanket rejection of every extra.

Analysis or suspected cause

Source-derived at the reported baseline. src/cli/adbCommands.ts:344 accepts any nonempty string as an extra. The parser at src/cli/adbCommands.ts:352 searches for two colons and throws a plain Error at src/cli/adbCommands.ts:356 when either delimiter is missing. This occurs before the shared execute call at src/cli/adbCommands.ts:368.

The execute wrapper at src/cli/adbCommands.ts:24 runs the shared service and projects its typed failure at src/cli/adbCommands.ts:35. Shared schema rejection at src/application/ProviderOperationExecution.ts:48 instead returns AnalysisInputError before provider execution. The delimiter throw bypasses that projection and reaches Incur's generic UNKNOWN handler. Source inspection explains the observed payload difference; the executable's stdout and exit status establish the failure.

Additional context

P2 is supported because this bounded input-error path violates a machine-readable classification and recovery contract. The command still rejects the input, and correcting the delimiter syntax proceeds to normal provider admission. No data loss, security boundary crossing, or downstream consumer failure was observed.

Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3210 ### 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 `rea start-adb-activity` rejects a nonempty `--extra` value with fewer than two colons, but its JSON response contains only `code: "UNKNOWN"` and a message. It omits the required `category`, `retryable`, and `remediation` fields from the shared error contract. The values `string:key`, `:`, and `string` each exited 1, wrote the incomplete JSON error to stdout, and wrote no stderr. All three payloads failed validation against the checked-in error schema. The unsupported-type control `bogus:key:value` exited 1 with a schema-valid `invalid_request` response. The valid-extra control `string:key:value` reached provider admission and returned a schema-valid `capability_unavailable` response for the deliberately missing adb executable. ### Reproduction 1. From a clean checkout at `58300885207133422af235e0f2b10658cf958b03`, use the repository's pinned Node.js and npm toolchain and prepare the standalone runtime: ```sh npm ci npm run build:cached ``` 2. Run this from the checkout root in a shell without `set -e`. It creates an isolated home and selects a nonexistent adb executable. No input files, real adb client, device, or emulator are needed. The first three inputs reproduce missing delimiters; the last two are controls. ```sh repro_dir="$(mktemp -d)" mkdir -p "$repro_dir/home" for extra in 'string:key' ':' 'string' 'bogus:key:value' 'string:key:value'; do printf 'extra=%s\n' "$extra" env HOME="$repro_dir/home" \ XDG_CONFIG_HOME="$repro_dir/home/config" \ XDG_CACHE_HOME="$repro_dir/home/cache" \ XDG_DATA_HOME="$repro_dir/home/data" \ REA_ADB_PATH="$repro_dir/missing-adb" \ node scripts/rea.mjs start-adb-activity emulator-5554 \ android.intent.action.VIEW --extra "$extra" --json printf 'exit=%s\n' "$?" done rm -rf "$repro_dir" ``` 3. Observe that each of the first three commands exits 1 with `UNKNOWN` and no category, retryability, or remediation. Compare the two controls, which retain canonical error fields. Verification used the prepared baseline runtime and locked dependencies. The clean-checkout install and build prerequisites above were not rerun during that verification. ### Expected behavior Malformed typed-extra syntax should return `code: "invalid_request"`, `category: "invalid_input"`, a nonempty message, a boolean `retryable`, and a nonempty `remediation.action`. The command should exit 1 before attempting a device operation. `docs/error-contract.schema.json` requires these fields for the invalid_request variant and does not allow UNKNOWN as an error code. Details are optional for invalid_request. `src/contracts/errorSchemas.ts:34` describes the stable schema shared by every CLI and MCP error surface. `AGENTS.md`, under Architecture and Cleanup, requires parsing unknown boundary values and modeling expected failures with the tagged error algebra and Result. The command's `start-adb-activity --help` documents repeatable `type:key:value` extras. ### Impact and scope Callers cannot classify these malformed-input failures or read retryability and recovery through the shared error contract. The reproduced defect is bounded to nonempty extras with fewer than two colons. Input rejection and exit status remain correct, and no device operation was observed for those malformed values. No downstream consumer crash was tested. Correcting the value to `type:key:value` is a practical workaround for submitting the intended request. The valid-extra control demonstrated normal provider admission, rather than a successful activity launch. That workaround does not restore canonical failure handling for callers that must process malformed input. ### REA version 6.4.0 (main at 58300885207133422af235e0f2b10658cf958b03) ### Runtime and platform Node 26.10.0; macOS 27.0 arm64. The Node version was measured. The OS and architecture are supplied platform context and were not independently established during verification. ### Target and artifact context CLI typed-extra parsing with serial `emulator-5554` and action `android.intent.action.VIEW`. The serial is a placeholder; no device or emulator was contacted. Each process used isolated HOME and XDG directories and an intentionally nonexistent REA_ADB_PATH. No binary or artifact input is required. ### Interface CLI ### Earliest failure stage Request parsing or validation ### Relevant output or evidence ```text extra=string:key {"code":"UNKNOWN","message":"--extra expects type:key:value, received: string:key"} exit=1 extra=bogus:key:value {"code":"invalid_request","category":"invalid_input","message":"Analysis input is invalid. Check the arguments and try again.","retryable":true,"remediation":{"action":"Correct the listed arguments and retry."}} exit=1 ``` ### Typed outcome or recovery expected Return a schema-valid invalid_request projection with category invalid_input, boolean retryability, and a nonempty remediation.action for each malformed delimiter case, while preserving exit 1 and rejection before provider execution. Keep canonical rejection for the unsupported-type control. Keep valid-extra parsing reaching provider admission and reporting the intentionally missing adb executable as capability_unavailable. These controls distinguish restored classification from blanket rejection of every extra. ### Analysis or suspected cause Source-derived at the reported baseline. `src/cli/adbCommands.ts:344` accepts any nonempty string as an extra. The parser at `src/cli/adbCommands.ts:352` searches for two colons and throws a plain Error at `src/cli/adbCommands.ts:356` when either delimiter is missing. This occurs before the shared execute call at `src/cli/adbCommands.ts:368`. The execute wrapper at `src/cli/adbCommands.ts:24` runs the shared service and projects its typed failure at `src/cli/adbCommands.ts:35`. Shared schema rejection at `src/application/ProviderOperationExecution.ts:48` instead returns AnalysisInputError before provider execution. The delimiter throw bypasses that projection and reaches Incur's generic UNKNOWN handler. Source inspection explains the observed payload difference; the executable's stdout and exit status establish the failure. ### Additional context P2 is supported because this bounded input-error path violates a machine-readable classification and recovery contract. The command still rejects the input, and correcting the delimiter syntax proceeds to normal provider admission. No data loss, security boundary crossing, or downstream consumer failure was observed.
bsakaguchi 2026-10-15 18:31:31 +00:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

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

TL;DR: Confirmed on Linux. Main still has this bug. Three bad --extra values return UNKNOWN with no category, retry flag or remediation, and they fail the schema.

Results

I ran your recipe on main efbc486b9 (#3606) (package version 6.5.0). It is 161 commits after your base 58300885. The code at src/cli/adbCommands.ts line 358 still throws a plain Error. The one commit that touched that file since your base, 864314ac8, did not change the throw.

I used five cases on Node 24.18.0 and on Node 26.11.1. Every run exited 1 with an empty stderr. I checked each stdout against docs/error-contract.schema.json with the repo's ajv 8.20.0.

Input to --extra What came back Schema
string:key UNKNOWN and a message only fails
: UNKNOWN and a message only fails
string UNKNOWN and a message only fails
bogus:key:value (control) invalid_request, invalid_input passes
string:key:value (control) capability_unavailable for the missing adb passes

The results match your report on both Node versions. On this box the three UNKNOWN payloads print over several lines, where your report shows one line. I did not look into why.

An open pull request, #3271 by paoValle, is titled "classify malformed adb --extra as invalid input". I only read that pull request's metadata. I did not build or run its branch.

Not run

  • Your base 58300885 (main already reproduces it).
  • A real adb client, a device, or an emulator.
  • macOS and Windows.

Thanks, coygeek, for the clear report and the controls.

Commands
npm ci
npm run build:cached
# once per case and Node version, fresh HOME each time
env -C /tmp/i3210/main HOME=/tmp/i3210/home/c1-n24 \
  XDG_CONFIG_HOME=/tmp/i3210/home/c1-n24/config \
  XDG_CACHE_HOME=/tmp/i3210/home/c1-n24/cache \
  XDG_DATA_HOME=/tmp/i3210/home/c1-n24/data \
  REA_ADB_PATH=/tmp/i3210/home/c1-n24/missing-adb \
  node scripts/rea.mjs start-adb-activity emulator-5554 \
  android.intent.action.VIEW --extra 'string:key' --json

I unrolled your loop into five runs. Your report names no schema command, so I wrote a short ajv script. It uses Ajv2020 from the repo.

Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.9
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 24.18.0 (build and runs), 26.11.1 (runs); npm 11.16.0
  • Main / your base: efbc486b9 / 58300885

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

<!-- gh-comment-id:6176653901 --> @CassieFox23 commented on GitHub (Oct 14, 2026): **TL;DR:** Confirmed on Linux. Main still has this bug. Three bad `--extra` values return `UNKNOWN` with no category, retry flag or remediation, and they fail the schema. ### Results I ran your recipe on main efbc486b9 (#3606) (package version 6.5.0). It is 161 commits after your base 58300885. The code at `src/cli/adbCommands.ts` line 358 still throws a plain `Error`. The one commit that touched that file since your base, 864314ac8, did not change the throw. I used five cases on Node 24.18.0 and on Node 26.11.1. Every run exited 1 with an empty stderr. I checked each stdout against `docs/error-contract.schema.json` with the repo's ajv 8.20.0. | Input to `--extra` | What came back | Schema | |---|---|---| | `string:key` | `UNKNOWN` and a message only | fails | | `:` | `UNKNOWN` and a message only | fails | | `string` | `UNKNOWN` and a message only | fails | | `bogus:key:value` (control) | `invalid_request`, `invalid_input` | passes | | `string:key:value` (control) | `capability_unavailable` for the missing adb | passes | The results match your report on both Node versions. On this box the three `UNKNOWN` payloads print over several lines, where your report shows one line. I did not look into why. An open pull request, #3271 by paoValle, is titled "classify malformed adb --extra as invalid input". I only read that pull request's metadata. I did not build or run its branch. ### Not run - Your base 58300885 (main already reproduces it). - A real adb client, a device, or an emulator. - macOS and Windows. Thanks, coygeek, for the clear report and the controls. <details> <summary>Commands</summary> ```sh npm ci npm run build:cached # once per case and Node version, fresh HOME each time env -C /tmp/i3210/main HOME=/tmp/i3210/home/c1-n24 \ XDG_CONFIG_HOME=/tmp/i3210/home/c1-n24/config \ XDG_CACHE_HOME=/tmp/i3210/home/c1-n24/cache \ XDG_DATA_HOME=/tmp/i3210/home/c1-n24/data \ REA_ADB_PATH=/tmp/i3210/home/c1-n24/missing-adb \ node scripts/rea.mjs start-adb-activity emulator-5554 \ android.intent.action.VIEW --extra 'string:key' --json ``` I unrolled your loop into five runs. Your report names no schema command, so I wrote a short ajv script. It uses Ajv2020 from the repo. </details> <details> <summary>Test setup</summary> - Box: Nobara 44 (Fedora 44 base), Linux 7.2.9 - CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads - RAM: 32 GB DDR4-3600 - Node: 24.18.0 (build and runs), 26.11.1 (runs); npm 11.16.0 - Main / your base: efbc486b9 / 58300885 </details> 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
Author
Owner

@morluto commented on GitHub (Oct 14, 2026):

Delivered on main in fffb07419.

Malformed ADB extras threw an untyped Error before operation projection. The CLI boundary now returns typed invalid input while retaining valid-extra and unsupported-type behavior.

Validation: ADB CLI and MCP admission regressions. Full exact-revision qualification passed.

<!-- gh-comment-id:6177647480 --> @morluto commented on GitHub (Oct 14, 2026): Delivered on main in [fffb07419](https://github.com/morluto/rea/commit/fffb0741936067530d1ce9777461cd53e87398c2). Malformed ADB extras threw an untyped Error before operation projection. The CLI boundary now returns typed invalid input while retaining valid-extra and unsupported-type behavior. Validation: ADB CLI and MCP admission regressions. Full exact-revision [qualification](https://github.com/morluto/rea/actions/runs/38629313022) passed.
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#1148
No description provided.