[GH-ISSUE #1766] [Bug] Headless IDA fails with unreadable_output while the worker reports a transient busy health #594

Closed
opened 2026-10-15 18:26:28 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @nikolay-dementiev on GitHub (Oct 11, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1766

I'm working on this: a fix (bounded wait while the worker reports busy) with a regression test at the session-client boundary. I'll open a PR shortly.

Before submitting

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

Area

Native analysis or decompilation

Observed behavior

Right after idb_open, the headless worker can answer server_health with a transient busy payload instead of its identity:

{"status":"busy","uptime_sec":1.041,"busy_tool":"config_json_get","busy_sec":0.0,"queued_calls":0}

A moment later the same call returns the full {"status":"ok","input_path":...,"idb_path":...,"imagebase":...,"auto_analysis_ready":true,"module":...}. REA parses the first answer with modernHealthSchema, so the request fails as a non-retryable unreadable_output:

code: unreadable_output, category: execution_failure, retryable: false
details.operation: list_procedures
details.reason: IDA MCP returned malformed or unsupported producer data: status: Invalid input: expected "ok"; input_path: Invalid input: expected string, received undefined; idb_path: ...; imagebase: ...; auto_analysis_ready: ...; module: ...

On this host it blocks the real-workflow lane: npm run verify:ida passes "production CLI and complete function Evidence" and then fails in "production MCP list_procedures".

Reproduction

On a built checkout of main (58e91e14b), with upstream ida-pro-mcp at c133c3853faa111a9b00ee615c013b720d0c4acd (the commit named in docs/testing.md) installed through pipx and this registration:

{
  "command": "<home>/.local/bin/idalib-mcp",
  "args": ["--stdio", "--max-workers", "1"],
  "mode": "headless",
  "env": { "IDADIR": "/Applications/IDA Professional 9.1.app/Contents/MacOS" }
}
clang -O0 -arch arm64 -o <dir>/inventory tests/conformance/ida/inventory.c
REA_IDA_MCP_CONFIG=<dir>/ida-mcp.json npm run verify:ida -- --target <dir>/inventory --procedure _rea_fixture_add --report <dir>/report.json

Result: {"passed": false, "mode": "headless", "checks": ["production CLI and complete function Evidence"], "failed_phase": "production MCP list_procedures"}.

The busy answer itself is visible with a plain stdio JSON-RPC client: initialize, idb_open (input_path, mode: "force_headless", preferred_session_id), then server_health with that database immediately; the first answer is the busy payload above, a later one is status: "ok".

Expected behavior

A busy worker is a transient state, not malformed producer data. REA waits for the identity (bounded by the registration's request deadline) or reports a retryable provider-busy outcome, and the real-workflow lane passes.

Impact and scope

Every headless session on a host where the post-open warmup is still running when REA reads health. Observed on macOS arm64; the Windows x64 real workflow in docs/testing.md did not show it, presumably because of timing (not verified).

REA version

rea-agents 6.4.0 from npm, and main at 58e91e14b.

Runtime and platform

macOS 26.5.2 (arm64), Node 26.3.0, npm 11.16.0; IDA Professional 9.1 (9.1.250226) with idalib activated; Python 3.14.0; ida-pro-mcp 2.0.0 at c133c3853.

Target and artifact context

tests/conformance/ida/inventory.c built with clang -O0 -arch arm64 (Mach-O; symbols _main, _rea_fixture_add). No private target data.

Interface

MCP (also reachable from the CLI when the first health read lands in the busy window).

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

See Observed behavior. The lane's --report file holds the full tool result; I can attach redacted excerpts.

Typed outcome or recovery expected

No unreadable_output for a busy worker: either the identity check proceeds after the worker becomes idle, or a retryable busy outcome with the busy tool named.

Analysis or suspected cause

Source-derived: #observe() in src/ida/IdaSessionClient.ts calls server_health once and parses it with modernHealthSchema (src/ida/IdaProtocolValues.ts), which requires status: "ok" and the identity fields. src/ida has no handling for status: "busy".

Experiment (local, not a proposed patch): re-reading server_health every 100 ms while it reports status: "busy" makes the full lane pass on this host: all five checks, including "owned database IDs absent from upstream discovery and private workspaces removed" and "original binary unchanged and never executed".

Additional context

With the fix, macOS arm64 + IDA 9.1 headless could be listed as a verified real workflow in docs/ida-provider.md and docs/testing.md.

Originally created by @nikolay-dementiev on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1766 > I'm working on this: a fix (bounded wait while the worker reports busy) with a regression test at the session-client boundary. I'll open a PR shortly. ### Before submitting - [x] I searched the open and closed issues and pull requests for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Native analysis or decompilation ### Observed behavior Right after `idb_open`, the headless worker can answer `server_health` with a transient busy payload instead of its identity: ```json {"status":"busy","uptime_sec":1.041,"busy_tool":"config_json_get","busy_sec":0.0,"queued_calls":0} ``` A moment later the same call returns the full `{"status":"ok","input_path":...,"idb_path":...,"imagebase":...,"auto_analysis_ready":true,"module":...}`. REA parses the first answer with `modernHealthSchema`, so the request fails as a non-retryable `unreadable_output`: ```text code: unreadable_output, category: execution_failure, retryable: false details.operation: list_procedures details.reason: IDA MCP returned malformed or unsupported producer data: status: Invalid input: expected "ok"; input_path: Invalid input: expected string, received undefined; idb_path: ...; imagebase: ...; auto_analysis_ready: ...; module: ... ``` On this host it blocks the real-workflow lane: `npm run verify:ida` passes "production CLI and complete function Evidence" and then fails in "production MCP list_procedures". ### Reproduction On a built checkout of `main` (58e91e14b), with upstream ida-pro-mcp at `c133c3853faa111a9b00ee615c013b720d0c4acd` (the commit named in docs/testing.md) installed through pipx and this registration: ```json { "command": "<home>/.local/bin/idalib-mcp", "args": ["--stdio", "--max-workers", "1"], "mode": "headless", "env": { "IDADIR": "/Applications/IDA Professional 9.1.app/Contents/MacOS" } } ``` ```bash clang -O0 -arch arm64 -o <dir>/inventory tests/conformance/ida/inventory.c REA_IDA_MCP_CONFIG=<dir>/ida-mcp.json npm run verify:ida -- --target <dir>/inventory --procedure _rea_fixture_add --report <dir>/report.json ``` Result: `{"passed": false, "mode": "headless", "checks": ["production CLI and complete function Evidence"], "failed_phase": "production MCP list_procedures"}`. The busy answer itself is visible with a plain stdio JSON-RPC client: `initialize`, `idb_open` (`input_path`, `mode: "force_headless"`, `preferred_session_id`), then `server_health` with that `database` immediately; the first answer is the busy payload above, a later one is `status: "ok"`. ### Expected behavior A busy worker is a transient state, not malformed producer data. REA waits for the identity (bounded by the registration's request deadline) or reports a retryable provider-busy outcome, and the real-workflow lane passes. ### Impact and scope Every headless session on a host where the post-open warmup is still running when REA reads health. Observed on macOS arm64; the Windows x64 real workflow in docs/testing.md did not show it, presumably because of timing (not verified). ### REA version rea-agents 6.4.0 from npm, and `main` at 58e91e14b. ### Runtime and platform macOS 26.5.2 (arm64), Node 26.3.0, npm 11.16.0; IDA Professional 9.1 (9.1.250226) with idalib activated; Python 3.14.0; ida-pro-mcp 2.0.0 at c133c3853. ### Target and artifact context `tests/conformance/ida/inventory.c` built with `clang -O0 -arch arm64` (Mach-O; symbols `_main`, `_rea_fixture_add`). No private target data. ### Interface MCP (also reachable from the CLI when the first health read lands in the busy window). ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence See Observed behavior. The lane's `--report` file holds the full tool result; I can attach redacted excerpts. ### Typed outcome or recovery expected No `unreadable_output` for a busy worker: either the identity check proceeds after the worker becomes idle, or a retryable busy outcome with the busy tool named. ### Analysis or suspected cause Source-derived: `#observe()` in `src/ida/IdaSessionClient.ts` calls `server_health` once and parses it with `modernHealthSchema` (`src/ida/IdaProtocolValues.ts`), which requires `status: "ok"` and the identity fields. `src/ida` has no handling for `status: "busy"`. Experiment (local, not a proposed patch): re-reading `server_health` every 100 ms while it reports `status: "busy"` makes the full lane pass on this host: all five checks, including "owned database IDs absent from upstream discovery and private workspaces removed" and "original binary unchanged and never executed". ### Additional context With the fix, macOS arm64 + IDA 9.1 headless could be listed as a verified real workflow in docs/ida-provider.md and docs/testing.md.
bsakaguchi 2026-10-15 18:26:28 +00:00
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#594
No description provided.