[GH-ISSUE #3347] [Bug] Apktool version-probe deadlines return a nonretryable capability error #1214

Closed
opened 2026-10-16 21:02:53 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

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

Area

Provider or capability discovery

Observed behavior

inspect-apktool-client turns a launcher version-probe timeout into a nonretryable capability_unavailable result with category unsupported_provider. The message says the launcher did not report a usable version and omits the timeout category and declared deadline, so a caller cannot distinguish a slow probe from incompatible provider configuration.

The slow launcher stops at the deadline. In the repeated local run, the CLI exited with code 1 after approximately 20.7 seconds. An immediate version-reporting control succeeded with version 2.7.0. These public CLI results establish timeout misclassification rather than a missing launcher or malformed version string.

Reproduction

  1. Start from a clean source checkout, select the baseline, install the locked dependencies, and build the runtime:
git clone https://github.com/morluto/rea.git rea-repro
cd rea-repro
git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063
npm ci
npm run build:cached
  1. From the repository root, create a local launcher that would report a valid version after 30 seconds and inspect it:
case_dir=$(mktemp -d)
mkdir "$case_dir/home"
cat > "$case_dir/slow-apktool" <<'JS'
#!/usr/bin/env node
setTimeout(() => { process.stdout.write('2.7.0\n'); }, 30000);
JS
chmod +x "$case_dir/slow-apktool"
HOME="$case_dir/home" TMPDIR="$case_dir" \
  REA_APKTOOL_COMMAND="$case_dir/slow-apktool" \
  node scripts/rea.mjs inspect-apktool-client --format json
printf 'CLI exit: %s\n' "$?"
  1. Observe that the launcher stops at the version probe's 20,000 ms deadline, but the CLI returns capability_unavailable, category unsupported_provider, and retryable: false, without details.timeout_ms.

  2. Replace the fixture's setTimeout statement with an immediate version response and repeat the same inspection as a discriminating control:

cat > "$case_dir/slow-apktool" <<'JS'
#!/usr/bin/env node
process.stdout.write('2.7.0\n');
JS
HOME="$case_dir/home" TMPDIR="$case_dir" \
  REA_APKTOOL_COMMAND="$case_dir/slow-apktool" \
  node scripts/rea.mjs inspect-apktool-client --format json
printf 'CLI exit: %s\n' "$?"

The immediate control reports version 2.7.0 successfully. The reproduction uses one fixture process and requires no real Apktool or Java engine. Dependencies and the compiled runtime were already present for the observed runs; step 1 supplies the clean-checkout setup.

Expected behavior

Expiration of the version probe's declared 20,000 ms deadline should remain a timeout in the public typed error contract. The caller should receive provider_timeout, category timeout, and details.timeout_ms: 20000, with timeout recovery guidance. A successful version response should still produce the normal client inspection result.

src/domain/analysisErrorCore.ts:150 defines declared-deadline expiration as AnalysisTimeoutError. src/domain/analysisErrorProjection.ts:203 maps it to provider_timeout, and src/domain/analysisErrorProjection.ts:467 retains timeout_ms. docs/user-visible-errors.csv:20 specifies recovery for expired analysis deadlines: "Analysis took too long. Try a smaller request, then run rea doctor if it continues."

Impact and scope

Impact level: P2, supported by the repeated public CLI reproduction and successful immediate control. A bounded provider readiness failure loses its timeout identity and recovery guidance. Callers receive a nonretryable provider classification for a deadline expiration. The reproduction does not establish a failure in normal promptly responding launchers.

Workaround status: unverified. The probe has no documented timeout override, and no caller-level workaround preserving the timeout's structured classification was verified.

REA version

6.4.0 (main at 8dde6370d0)

Runtime and platform

Node.js v26.10.0, macOS 27.0.1 arm64.

Target and artifact context

A local executable fixture selected through REA_APKTOOL_COMMAND, with an isolated home and temporary directory. No APK, real Apktool installation, or Java engine is needed; the failure occurs during launcher version inspection.

Interface

CLI

Earliest failure stage

Setup or provider admission

Relevant output or evidence

The repeated slow-launcher run returned this error and exited with code 1 after approximately 20.7 seconds:

{
  "code": "capability_unavailable",
  "category": "unsupported_provider",
  "message": "The selected apktool launcher did not report a usable version.",
  "retryable": false,
  "remediation": {
    "action": "The selected apktool launcher did not report a usable version."
  },
  "details": {
    "provider_id": "apktool",
    "operation": "inspect_apktool_client",
    "reason": "The selected apktool launcher did not report a usable version."
  }
}

The result contains neither the timeout code nor the deadline. The immediate control successfully reports version 2.7.0.

Typed outcome or recovery expected

Repeat the slow-launcher inspection. It should stop at the same bounded deadline and return provider_timeout, category timeout, and the declared deadline in details.timeout_ms, with timeout recovery guidance. The immediate control must still return a successful inspection, and a missing launcher must still receive its missing-provider diagnostic.

Analysis or suspected cause

Source-derived reasoning: src/apktool/ApktoolConfiguration.ts:256 handles version-probe failures, and its catch path converts a timeout into version_unresolved before the provider's public refusal projection. That conversion loses the timeout identity before the shared typed error projection can retain the deadline. The repeated public CLI inspection and successful control are the primary failure evidence; the conversion explanation comes from source inspection.

Additional context

  • Related: #1774, closed as completed, concerns Windows batch launchers failing to spawn with EINVAL; this report concerns a successfully started launcher whose declared deadline expires.
  • Related: #1945, closed as completed, concerns missing-launcher remediation and relative-path configuration failures; this report concerns preserving the timeout code, category, and deadline.
  • Related: #1993, closed as completed, concerns a Darwin helper compiler failure falsely reported as a timeout; this report concerns an actual Apktool timeout falsely reported as a capability failure.
  • Related: #3068, closed as completed, concerns incorrect Apktool availability in binary_session; this report concerns the direct inspection result after an expired probe.
  • Related: #3008 requests broader doctor provider discovery; this report concerns the typed error from an already selected Apktool launcher.
  • Related: #100, closed as completed, defines the broader structured error contract; this report identifies a concrete Apktool deadline conversion that loses timeout details.
Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3347 ### 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 Provider or capability discovery ### Observed behavior `inspect-apktool-client` turns a launcher version-probe timeout into a nonretryable `capability_unavailable` result with category `unsupported_provider`. The message says the launcher did not report a usable version and omits the timeout category and declared deadline, so a caller cannot distinguish a slow probe from incompatible provider configuration. The slow launcher stops at the deadline. In the repeated local run, the CLI exited with code 1 after approximately 20.7 seconds. An immediate version-reporting control succeeded with version `2.7.0`. These public CLI results establish timeout misclassification rather than a missing launcher or malformed version string. ### Reproduction 1. Start from a clean source checkout, select the baseline, install the locked dependencies, and build the runtime: ```sh git clone https://github.com/morluto/rea.git rea-repro cd rea-repro git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063 npm ci npm run build:cached ``` 2. From the repository root, create a local launcher that would report a valid version after 30 seconds and inspect it: ```sh case_dir=$(mktemp -d) mkdir "$case_dir/home" cat > "$case_dir/slow-apktool" <<'JS' #!/usr/bin/env node setTimeout(() => { process.stdout.write('2.7.0\n'); }, 30000); JS chmod +x "$case_dir/slow-apktool" HOME="$case_dir/home" TMPDIR="$case_dir" \ REA_APKTOOL_COMMAND="$case_dir/slow-apktool" \ node scripts/rea.mjs inspect-apktool-client --format json printf 'CLI exit: %s\n' "$?" ``` 3. Observe that the launcher stops at the version probe's 20,000 ms deadline, but the CLI returns `capability_unavailable`, category `unsupported_provider`, and `retryable: false`, without `details.timeout_ms`. 4. Replace the fixture's `setTimeout` statement with an immediate version response and repeat the same inspection as a discriminating control: ```sh cat > "$case_dir/slow-apktool" <<'JS' #!/usr/bin/env node process.stdout.write('2.7.0\n'); JS HOME="$case_dir/home" TMPDIR="$case_dir" \ REA_APKTOOL_COMMAND="$case_dir/slow-apktool" \ node scripts/rea.mjs inspect-apktool-client --format json printf 'CLI exit: %s\n' "$?" ``` The immediate control reports version `2.7.0` successfully. The reproduction uses one fixture process and requires no real Apktool or Java engine. Dependencies and the compiled runtime were already present for the observed runs; step 1 supplies the clean-checkout setup. ### Expected behavior Expiration of the version probe's declared 20,000 ms deadline should remain a timeout in the public typed error contract. The caller should receive `provider_timeout`, category `timeout`, and `details.timeout_ms: 20000`, with timeout recovery guidance. A successful version response should still produce the normal client inspection result. `src/domain/analysisErrorCore.ts:150` defines declared-deadline expiration as `AnalysisTimeoutError`. `src/domain/analysisErrorProjection.ts:203` maps it to `provider_timeout`, and `src/domain/analysisErrorProjection.ts:467` retains `timeout_ms`. `docs/user-visible-errors.csv:20` specifies recovery for expired analysis deadlines: "Analysis took too long. Try a smaller request, then run `rea doctor` if it continues." ### Impact and scope Impact level: P2, supported by the repeated public CLI reproduction and successful immediate control. A bounded provider readiness failure loses its timeout identity and recovery guidance. Callers receive a nonretryable provider classification for a deadline expiration. The reproduction does not establish a failure in normal promptly responding launchers. Workaround status: unverified. The probe has no documented timeout override, and no caller-level workaround preserving the timeout's structured classification was verified. ### REA version 6.4.0 (main at 8dde6370d0809ad04cda3342d4e6f290f48aa063) ### Runtime and platform Node.js v26.10.0, macOS 27.0.1 arm64. ### Target and artifact context A local executable fixture selected through `REA_APKTOOL_COMMAND`, with an isolated home and temporary directory. No APK, real Apktool installation, or Java engine is needed; the failure occurs during launcher version inspection. ### Interface CLI ### Earliest failure stage Setup or provider admission ### Relevant output or evidence The repeated slow-launcher run returned this error and exited with code 1 after approximately 20.7 seconds: ```text { "code": "capability_unavailable", "category": "unsupported_provider", "message": "The selected apktool launcher did not report a usable version.", "retryable": false, "remediation": { "action": "The selected apktool launcher did not report a usable version." }, "details": { "provider_id": "apktool", "operation": "inspect_apktool_client", "reason": "The selected apktool launcher did not report a usable version." } } ``` The result contains neither the timeout code nor the deadline. The immediate control successfully reports version `2.7.0`. ### Typed outcome or recovery expected Repeat the slow-launcher inspection. It should stop at the same bounded deadline and return `provider_timeout`, category `timeout`, and the declared deadline in `details.timeout_ms`, with timeout recovery guidance. The immediate control must still return a successful inspection, and a missing launcher must still receive its missing-provider diagnostic. ### Analysis or suspected cause Source-derived reasoning: `src/apktool/ApktoolConfiguration.ts:256` handles version-probe failures, and its catch path converts a timeout into `version_unresolved` before the provider's public refusal projection. That conversion loses the timeout identity before the shared typed error projection can retain the deadline. The repeated public CLI inspection and successful control are the primary failure evidence; the conversion explanation comes from source inspection. ### Additional context - Related: [#1774](https://github.com/morluto/rea/issues/1774), closed as completed, concerns Windows batch launchers failing to spawn with EINVAL; this report concerns a successfully started launcher whose declared deadline expires. - Related: [#1945](https://github.com/morluto/rea/issues/1945), closed as completed, concerns missing-launcher remediation and relative-path configuration failures; this report concerns preserving the timeout code, category, and deadline. - Related: [#1993](https://github.com/morluto/rea/issues/1993), closed as completed, concerns a Darwin helper compiler failure falsely reported as a timeout; this report concerns an actual Apktool timeout falsely reported as a capability failure. - Related: [#3068](https://github.com/morluto/rea/issues/3068), closed as completed, concerns incorrect Apktool availability in `binary_session`; this report concerns the direct inspection result after an expired probe. - Related: [#3008](https://github.com/morluto/rea/issues/3008) requests broader doctor provider discovery; this report concerns the typed error from an already selected Apktool launcher. - Related: [#100](https://github.com/morluto/rea/issues/100), closed as completed, defines the broader structured error contract; this report identifies a concrete Apktool deadline conversion that loses timeout details.
Author
Owner

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

TL;DR: I can reproduce this on Linux, on current main. A slow Apktool launcher hits its 20,000 ms limit. REA then reports a capability error that is not retryable, with no timeout code.

Results

I tested main at efbc486b9 (#3606), REA 6.5.0. The launcher is a script that prints 2.7.0 after 30 seconds. Each run used a fresh empty home.

Case Node Exit Time What came back Matches the issue
Slow launcher 24.18.0 1 20.8 s Capability error, not retryable, no timeout_ms Yes
Slow launcher 26.11.1 1 20.7 s Same as the first row Yes
Slow launcher 22.23.1 1 21.0 s Same as the first row Yes
Immediate launcher (control) 24.18.0 0 0.8 s Normal result, version 2.7.0 Yes
Missing launcher 24.18.0 1 0.8 s "launcher was not found", with advice to set REA_APKTOOL_COMMAND Yes

The message for the slow case reads "did not report a usable version". It never says timeout. It has no details.timeout_ms. The slow runs took about 20.7 to 21.0 s and the control took 0.8 s. So the slow runs stopped at the 20,000 ms limit plus the normal start time.

By reading the source (not run): the catch block in src/apktool/ApktoolConfiguration.ts has branches for cancel and for a missing launcher. Every other failure becomes version_unresolved. A timed-out probe reaches that path with code ETIMEDOUT in src/process/ExecFileOutput.ts, so REA knows it timed out, then drops that.

One commit changed this file since the issue: e5deb832c. It left the timeout path alone.

Not run

  • The issue's commit 8dde6370d. The bug showed on main, so there was no fix to find.
  • macOS and Windows.
  • A real Apktool and Java.
  • The repo test suites.

Thanks, Coy Geek, for the clear report and the control case.

Commands
git -C ~/code/rea-mirror/rea.git archive efbc486b9bf8ab46da16fdd6ed88128849e30e81 | tar -x -C /tmp/i3347/main
env -C /tmp/i3347/main npm ci                    # exit 0
env -C /tmp/i3347/main npm run build:cached      # exit 0
# slow-apktool: setTimeout(() => { process.stdout.write('2.7.0\n'); }, 30000);
# fast-apktool: process.stdout.write('2.7.0\n');
HOME=/tmp/i3347/home/a TMPDIR=/tmp/i3347/cases \
  REA_APKTOOL_COMMAND=/tmp/i3347/cases/slow-apktool \
  env -C /tmp/i3347/main node scripts/rea.mjs inspect-apktool-client --format json   # exit 1

The control used fast-apktool and exited 0. The missing case pointed at a path that does not exist and exited 1. Node 22 and 26 ran the slow case with their own binaries.

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: 22.23.1, 24.18.0, 26.11.1 (build on 24.18.0)
  • Head: efbc486b9 (issue commit 8dde6370d was not run)
  • Other: no benchmark process was running when each run started; other agents may have shared the box

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

<!-- gh-comment-id:6176661107 --> @CassieFox23 commented on GitHub (Oct 14, 2026): **TL;DR:** I can reproduce this on Linux, on current main. A slow Apktool launcher hits its 20,000 ms limit. REA then reports a capability error that is not retryable, with no timeout code. ### Results I tested main at efbc486b9 (#3606), REA 6.5.0. The launcher is a script that prints 2.7.0 after 30 seconds. Each run used a fresh empty home. | Case | Node | Exit | Time | What came back | Matches the issue | | --- | --- | --- | --- | --- | --- | | Slow launcher | 24.18.0 | 1 | 20.8 s | Capability error, not retryable, no timeout_ms | Yes | | Slow launcher | 26.11.1 | 1 | 20.7 s | Same as the first row | Yes | | Slow launcher | 22.23.1 | 1 | 21.0 s | Same as the first row | Yes | | Immediate launcher (control) | 24.18.0 | 0 | 0.8 s | Normal result, version 2.7.0 | Yes | | Missing launcher | 24.18.0 | 1 | 0.8 s | "launcher was not found", with advice to set REA_APKTOOL_COMMAND | Yes | The message for the slow case reads "did not report a usable version". It never says timeout. It has no `details.timeout_ms`. The slow runs took about 20.7 to 21.0 s and the control took 0.8 s. So the slow runs stopped at the 20,000 ms limit plus the normal start time. By reading the source (not run): the catch block in `src/apktool/ApktoolConfiguration.ts` has branches for cancel and for a missing launcher. Every other failure becomes `version_unresolved`. A timed-out probe reaches that path with code `ETIMEDOUT` in `src/process/ExecFileOutput.ts`, so REA knows it timed out, then drops that. One commit changed this file since the issue: e5deb832c. It left the timeout path alone. ### Not run - The issue's commit 8dde6370d. The bug showed on main, so there was no fix to find. - macOS and Windows. - A real Apktool and Java. - The repo test suites. Thanks, Coy Geek, for the clear report and the control case. <details> <summary>Commands</summary> ```sh git -C ~/code/rea-mirror/rea.git archive efbc486b9bf8ab46da16fdd6ed88128849e30e81 | tar -x -C /tmp/i3347/main env -C /tmp/i3347/main npm ci # exit 0 env -C /tmp/i3347/main npm run build:cached # exit 0 # slow-apktool: setTimeout(() => { process.stdout.write('2.7.0\n'); }, 30000); # fast-apktool: process.stdout.write('2.7.0\n'); HOME=/tmp/i3347/home/a TMPDIR=/tmp/i3347/cases \ REA_APKTOOL_COMMAND=/tmp/i3347/cases/slow-apktool \ env -C /tmp/i3347/main node scripts/rea.mjs inspect-apktool-client --format json # exit 1 ``` The control used `fast-apktool` and exited 0. The missing case pointed at a path that does not exist and exited 1. Node 22 and 26 ran the slow case with their own binaries. </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: 22.23.1, 24.18.0, 26.11.1 (build on 24.18.0) - Head: efbc486b9 (issue commit 8dde6370d was not run) - Other: no benchmark process was running when each run started; other agents may have shared the box </details> 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
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#1214
No description provided.