[GH-ISSUE #7164] [Bug] binary_session fails entirely on Linux when ps is not on REA's PATH #4288

Closed
opened 2026-10-31 00:48:33 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @devreddy1015 on GitHub (Oct 25, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7164

Area

MCP server / binary_session status; apktool availability probe; Linux process ownership.

Observed behavior

On Linux, when ps is not on REA's PATH, binary_session with no arguments fails as a whole. No session or provider status is returned:

{"error":{"code":"capability_unavailable","category":"unsupported_provider","message":"Linux process ownership inspection requires a procps-compatible ps on REA's PATH before launching a child: spawn ps ENOENT","retryable":false,"details":{"provider_id":"process-ownership","operation":"inspect_apktool_client", ...}}}

This happens even though Apktool is not installed. With a PATH that contains only a ps symlink, the same call succeeds and returns status.

Reproduction

In a source checkout, run npm run build:cached, save this script as session.mjs in the checkout root, and run it from there with node session.mjs "<PATH>". It starts rea mcp with only HOME and the selected PATH, then calls binary_session {}:

// session.mjs <PATH>
import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
const home = mkdtempSync(join(tmpdir(), "rea-session-ps-"));
const transport = new StdioClientTransport({
  command: process.execPath,
  args: ["scripts/rea.mjs", "mcp"],
  env: { HOME: home, PATH: process.argv[2] ?? "" },
  stderr: "ignore",
});
const client = new Client({ name: "ps-repro", version: "1" });
await client.connect(transport);
const result = await client.callTool({ name: "binary_session", arguments: {} });
console.log(result.isError ?? false, result.isError ? result.content[0].text.slice(0, 200) : "status returned");
await client.close();

Observed (summarized):

PATH=""                         -> isError: true, capability_unavailable (operation inspect_apktool_client)
PATH=<dir with only a ps link>  -> isError: false, status returned

Expected behavior

docs/installation.md ("Linux owned-process prerequisite") and the README scope the ps requirement to Ghidra, JADX, firmware tool launches and static JavaScript/Electron analysis. A missing ps "causes a refusal before the supervised child starts" for those workflows.

binary_session is the discovery and status call. I expected it to return status and to report the affected tools as unavailable with this reason. A failure in one optional availability probe should not hide every other provider's status.

For comparison, with ps on PATH and no Apktool installed, the status already reports the apktool tools this way:

{"names":["decode_android_resources","inspect_apktool_client"],"available":false,"reason":"provider_unavailable","remediation":"The selected apktool launcher was not found: apktool"}

Impact and scope

Every binary_session status call fails on a Linux host without procps, such as a minimal container image. Agents call this tool first, so the session reports no capabilities instead of the specific missing prerequisite.

Only Linux was checked. macOS does not use ps for this preparation.

REA version

main at db4d3ab (rea-agents 6.8.0), source checkout.

Runtime and platform

Linux x64 (kernel 7.2), Node.js 26.12.1.

Target and artifact context

None. No target was opened.

Interface

MCP (stdio).

Earliest failure stage

The binary_session provider availability probes, before session status is assembled.

Relevant output or evidence

The error output is above. This also currently breaks CI on main: tests/acceptance/setup/launcherAliasesCli.test.ts starts the generated MCP command with PATH="" and asserts that binary_session succeeds. The test-side repair is in a separate PR.

Typed outcome or recovery expected

A successful binary_session result in which the tools whose probe needs ps are listed with available: false and the existing process-ownership reason as remediation. Internally, the probe could return status: "unavailable" with a code such as runtime_unavailable or unsupported_host. The other providers' availability should be unaffected.

Analysis or suspected cause

This is source-derived and not verified beyond the reproduction above:

  • src/server/registerSessionStatusTool.ts gathers the android, adb, apktool, jeb and EVM probes with a single Promise.all. Any probe that throws an AnalysisError turns the whole call into an error result.
  • src/apktool/ApktoolProvider.ts #inspectAvailability maps only ApktoolConfigurationFailure to an unavailable result and rethrows everything else.
  • On POSIX, resolveApktoolCommand returns the bare apktool command without checking PATH. The probe therefore always attempts a supervised launch, and Linux ownership preparation (src/process/ProcessOwnershipObservation.ts, prepare) fails first when ps is absent. versionProbeFailure returns that AnalysisError unchanged.

A fix could classify the ownership-preparation refusal in the apktool probe, or make the status tool tolerate a probe's capability failure. I have not chosen between them, because which layer owns this classification is a maintainer decision.

Additional context

Related: #6082 (closed) classified the same missing-ps capability for source-map tracing.

Originally created by @devreddy1015 on GitHub (Oct 25, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7164 ### Area MCP server / `binary_session` status; apktool availability probe; Linux process ownership. ### Observed behavior On Linux, when `ps` is not on REA's `PATH`, `binary_session` with no arguments fails as a whole. No session or provider status is returned: ```json {"error":{"code":"capability_unavailable","category":"unsupported_provider","message":"Linux process ownership inspection requires a procps-compatible ps on REA's PATH before launching a child: spawn ps ENOENT","retryable":false,"details":{"provider_id":"process-ownership","operation":"inspect_apktool_client", ...}}} ``` This happens even though Apktool is not installed. With a `PATH` that contains only a `ps` symlink, the same call succeeds and returns status. ### Reproduction In a source checkout, run `npm run build:cached`, save this script as `session.mjs` in the checkout root, and run it from there with `node session.mjs "<PATH>"`. It starts `rea mcp` with only `HOME` and the selected `PATH`, then calls `binary_session {}`: ```js // session.mjs <PATH> import { mkdtempSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Client } from "@modelcontextprotocol/client"; import { StdioClientTransport } from "@modelcontextprotocol/client/stdio"; const home = mkdtempSync(join(tmpdir(), "rea-session-ps-")); const transport = new StdioClientTransport({ command: process.execPath, args: ["scripts/rea.mjs", "mcp"], env: { HOME: home, PATH: process.argv[2] ?? "" }, stderr: "ignore", }); const client = new Client({ name: "ps-repro", version: "1" }); await client.connect(transport); const result = await client.callTool({ name: "binary_session", arguments: {} }); console.log(result.isError ?? false, result.isError ? result.content[0].text.slice(0, 200) : "status returned"); await client.close(); ``` Observed (summarized): ```text PATH="" -> isError: true, capability_unavailable (operation inspect_apktool_client) PATH=<dir with only a ps link> -> isError: false, status returned ``` ### Expected behavior `docs/installation.md` ("Linux owned-process prerequisite") and the README scope the `ps` requirement to Ghidra, JADX, firmware tool launches and static JavaScript/Electron analysis. A missing `ps` "causes a refusal before the supervised child starts" for those workflows. `binary_session` is the discovery and status call. I expected it to return status and to report the affected tools as unavailable with this reason. A failure in one optional availability probe should not hide every other provider's status. For comparison, with `ps` on `PATH` and no Apktool installed, the status already reports the apktool tools this way: ```json {"names":["decode_android_resources","inspect_apktool_client"],"available":false,"reason":"provider_unavailable","remediation":"The selected apktool launcher was not found: apktool"} ``` ### Impact and scope Every `binary_session` status call fails on a Linux host without procps, such as a minimal container image. Agents call this tool first, so the session reports no capabilities instead of the specific missing prerequisite. Only Linux was checked. macOS does not use `ps` for this preparation. ### REA version `main` at db4d3ab (rea-agents 6.8.0), source checkout. ### Runtime and platform Linux x64 (kernel 7.2), Node.js 26.12.1. ### Target and artifact context None. No target was opened. ### Interface MCP (stdio). ### Earliest failure stage The `binary_session` provider availability probes, before session status is assembled. ### Relevant output or evidence The error output is above. This also currently breaks CI on `main`: `tests/acceptance/setup/launcherAliasesCli.test.ts` starts the generated MCP command with `PATH=""` and asserts that `binary_session` succeeds. The test-side repair is in a separate PR. ### Typed outcome or recovery expected A successful `binary_session` result in which the tools whose probe needs `ps` are listed with `available: false` and the existing process-ownership reason as remediation. Internally, the probe could return `status: "unavailable"` with a code such as `runtime_unavailable` or `unsupported_host`. The other providers' availability should be unaffected. ### Analysis or suspected cause This is source-derived and not verified beyond the reproduction above: - `src/server/registerSessionStatusTool.ts` gathers the android, adb, apktool, jeb and EVM probes with a single `Promise.all`. Any probe that throws an `AnalysisError` turns the whole call into an error result. - `src/apktool/ApktoolProvider.ts` `#inspectAvailability` maps only `ApktoolConfigurationFailure` to an unavailable result and rethrows everything else. - On POSIX, `resolveApktoolCommand` returns the bare `apktool` command without checking `PATH`. The probe therefore always attempts a supervised launch, and Linux ownership preparation (`src/process/ProcessOwnershipObservation.ts`, `prepare`) fails first when `ps` is absent. `versionProbeFailure` returns that `AnalysisError` unchanged. A fix could classify the ownership-preparation refusal in the apktool probe, or make the status tool tolerate a probe's capability failure. I have not chosen between them, because which layer owns this classification is a maintainer decision. ### Additional context Related: #6082 (closed) classified the same missing-`ps` capability for source-map tracing.
Author
Owner

@chordpli commented on GitHub (Oct 25, 2026):

Reproduced on current main (1173c0a9d) in a Linux arm64 container (node:24-bookworm, Node 24.22.1, kernel 7.0.12-linuxkit), running the session.mjs from this report unchanged after npm run build:cached:

PATH=""                         -> isError: true, capability_unavailable, operation inspect_apktool_client, "spawn ps ENOENT"
PATH=<dir with only a ps link>  -> isError: false, status returned
PATH=<full>                     -> isError: false, status returned

Source-derived (not yet verified by a fix): the Linux prepare step in src/process/ProcessOwnershipObservation.ts throws AnalysisCapabilityUnavailableError when ps cannot be spawned. ApktoolProvider.inspectAvailability maps only ApktoolConfigurationFailure to an availability result and rethrows everything else, so the error escapes the Promise.all in registerSessionStatusTool.ts and the whole binary_session call fails instead of one provider group being reported unavailable.

I'm taking this one. Plan: report the missing host prerequisite as per-provider unavailability carrying the ps reason, keep the remaining provider status intact, and verify through the same session.mjs run in the Linux container before and after. I'll link the PR here.

<!-- gh-comment-id:6404997563 --> @chordpli commented on GitHub (Oct 25, 2026): Reproduced on current `main` (`1173c0a9d`) in a Linux arm64 container (`node:24-bookworm`, Node 24.22.1, kernel 7.0.12-linuxkit), running the `session.mjs` from this report unchanged after `npm run build:cached`: ```text PATH="" -> isError: true, capability_unavailable, operation inspect_apktool_client, "spawn ps ENOENT" PATH=<dir with only a ps link> -> isError: false, status returned PATH=<full> -> isError: false, status returned ``` Source-derived (not yet verified by a fix): the Linux `prepare` step in `src/process/ProcessOwnershipObservation.ts` throws `AnalysisCapabilityUnavailableError` when `ps` cannot be spawned. `ApktoolProvider.inspectAvailability` maps only `ApktoolConfigurationFailure` to an availability result and rethrows everything else, so the error escapes the `Promise.all` in `registerSessionStatusTool.ts` and the whole `binary_session` call fails instead of one provider group being reported unavailable. I'm taking this one. Plan: report the missing host prerequisite as per-provider unavailability carrying the `ps` reason, keep the remaining provider status intact, and verify through the same `session.mjs` run in the Linux container before and after. I'll link the PR here.
Author
Owner

@chordpli commented on GitHub (Oct 25, 2026):

Fix is up as a draft: #7180. In a Linux arm64 container (node:24-bookworm) the issue's session.mjs with PATH="" now returns status; the Apktool and JADX groups report provider_unavailable with the ps reason and remediation, and the adb group keeps its own status. The same run against main 1173c0a9d still fails as a whole. Before/after output is in the PR body.

<!-- gh-comment-id:6405175637 --> @chordpli commented on GitHub (Oct 25, 2026): Fix is up as a draft: #7180. In a Linux arm64 container (node:24-bookworm) the issue's `session.mjs` with `PATH=""` now returns status; the Apktool and JADX groups report `provider_unavailable` with the `ps` reason and remediation, and the adb group keeps its own status. The same run against `main` `1173c0a9d` still fails as a whole. Before/after output is in the PR body.
Author
Owner

@XinwangTao commented on GitHub (Oct 26, 2026):

关于"哪个层负责分类"这个维护者决策点,倾向支持在 status 工具层容忍 capability failure:apktool 不是唯一会在 probe 里触发 ownership 准备的提供方(JADX/firmware 同理),把分类下推到每个 provider 会重复三遍。在 registerSessionStatusTool.ts 的 Promise.all 里对 AnalysisCapabilityUnavailableError 做聚合降级(记录 unavailable + 原因,不中断整体状态汇总)即可覆盖本 issue 且天然免疫未来的同类 probe。另建议在 PR #7180 的断言里同时覆盖:缺少 ps 时无关组(如 adb/EVM)状态保持 available 语义不变,避免"整体不报错但状态被污染"的回归。

<!-- gh-comment-id:6411355286 --> @XinwangTao commented on GitHub (Oct 26, 2026): 关于"哪个层负责分类"这个维护者决策点,倾向支持在 status 工具层容忍 capability failure:apktool 不是唯一会在 probe 里触发 ownership 准备的提供方(JADX/firmware 同理),把分类下推到每个 provider 会重复三遍。在 registerSessionStatusTool.ts 的 Promise.all 里对 AnalysisCapabilityUnavailableError 做聚合降级(记录 unavailable + 原因,不中断整体状态汇总)即可覆盖本 issue 且天然免疫未来的同类 probe。另建议在 PR #7180 的断言里同时覆盖:缺少 ps 时无关组(如 adb/EVM)状态保持 available 语义不变,避免"整体不报错但状态被污染"的回归。
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#4288
No description provided.