[GH-ISSUE #8203] [Bug] open_binary with automatic provider selection succeeds, but later calls return target_unavailable #6481

Open
opened 2026-11-01 21:11:31 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @xuanhieu on GitHub (Oct 30, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8203

Before submitting

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

Area

MCP or agent integration

Interface

MCP

Earliest failure stage

Setup or provider admission

Observed behavior

open_binary without provider_id, on a stripped arm64 Mach-O, returns success. The next call (binary_overview, list_procedures) returns target_unavailable. At that time no deep provider was usable: Ghidra had the environment problem from issue 2, and Hopper was blocked by macOS Automation (TCC: "Not authorized to send Apple events to Hopper Disassembler").

Expected behavior

When automatic selection admits no deep provider, open_binary should fail with a typed provider_unavailable that lists each rejection, as it does when provider_id is given explicitly. It should not report a session that cannot be used.

Impact and scope

A silent failure. The agent believes a target is open, then spends several calls diagnosing it.

REA version, runtime and platform

REA: rea-agents 6.8.0 (npm)
Runtime: Node.js 24.22.1
Platform: macOS 27.2 (Darwin), arm64
Providers: Ghidra 12.1.4 (natives built locally with support/gradle buildNatives), OpenJDK 25.0.5, Hopper 6.6.0 demo
Client: Claude Code 2.1.309–2.1.314
Originally created by @xuanhieu on GitHub (Oct 30, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8203 ### 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 MCP or agent integration ### Interface MCP ### Earliest failure stage Setup or provider admission ### Observed behavior `open_binary` without `provider_id`, on a stripped arm64 Mach-O, returns success. The next call (`binary_overview`, `list_procedures`) returns `target_unavailable`. At that time no deep provider was usable: Ghidra had the environment problem from issue 2, and Hopper was blocked by macOS Automation (TCC: "Not authorized to send Apple events to Hopper Disassembler"). ### Expected behavior When automatic selection admits no deep provider, `open_binary` should fail with a typed `provider_unavailable` that lists each rejection, as it does when `provider_id` is given explicitly. It should not report a session that cannot be used. ### Impact and scope A silent failure. The agent believes a target is open, then spends several calls diagnosing it. ### REA version, runtime and platform ``` REA: rea-agents 6.8.0 (npm) Runtime: Node.js 24.22.1 Platform: macOS 27.2 (Darwin), arm64 Providers: Ghidra 12.1.4 (natives built locally with support/gradle buildNatives), OpenJDK 25.0.5, Hopper 6.6.0 demo Client: Claude Code 2.1.309–2.1.314 ```
Author
Owner

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

Follow-up on current main 245a5818, macOS arm64, using an unexecuted self-built Mach-O and real stdio MCP. I explicitly set the Hopper launcher to a nonexistent path and omitted Ghidra, IDA and Kuna configuration; this controls unavailability but does not reproduce the reported Hopper Automation denial.

  • Automatic open_binary succeeded and returned the target identity. binary_session then reported open: true, analysis_provider_binding: null, and the four provider availability reasons. Both binary_overview and list_procedures returned provider_unavailable, with all four rejections in details, rather than the original report's target_unavailable.
  • In that same unbound session, inspect_macho succeeded via native-macos and produced Mach-O observations. Thus an open session can still serve useful provider-independent work; automatically failing all such opens would remove this workflow.
  • With an explicit unavailable provider_id: "ghidra", open_binary failed with provider_unavailable and no target was open. In a fresh server with Ghidra 12.1.4 and Java configured, automatic open bound Ghidra; binary_overview and list_procedures succeeded.

The remaining UX question for this controlled case is whether the successful automatic-open response should make its unbound deep-analysis state visible immediately, while preserving shallow inspection, rather than requiring a separate binary_session call or a failed deep request. The original TCC failure mode still needs its own reproduction; these results should not be treated as a fix for it. The input hash was unchanged.

<!-- gh-comment-id:6540527685 --> @morluto commented on GitHub (Oct 31, 2026): Follow-up on current main `245a5818`, macOS arm64, using an unexecuted self-built Mach-O and real stdio MCP. I explicitly set the Hopper launcher to a nonexistent path and omitted Ghidra, IDA and Kuna configuration; this controls unavailability but does **not** reproduce the reported Hopper Automation denial. * Automatic `open_binary` succeeded and returned the target identity. `binary_session` then reported `open: true`, `analysis_provider_binding: null`, and the four provider availability reasons. Both `binary_overview` and `list_procedures` returned **`provider_unavailable`**, with all four rejections in `details`, rather than the original report's `target_unavailable`. * In that same unbound session, `inspect_macho` succeeded via `native-macos` and produced Mach-O observations. Thus an open session can still serve useful provider-independent work; automatically failing all such opens would remove this workflow. * With an explicit unavailable `provider_id: "ghidra"`, `open_binary` failed with `provider_unavailable` and no target was open. In a fresh server with Ghidra 12.1.4 and Java configured, automatic open bound Ghidra; `binary_overview` and `list_procedures` succeeded. The remaining UX question for this controlled case is whether the successful automatic-open response should make its **unbound deep-analysis state** visible immediately, while preserving shallow inspection, rather than requiring a separate `binary_session` call or a failed deep request. The original TCC failure mode still needs its own reproduction; these results should not be treated as a fix for it. The input hash was unchanged.
Author
Owner

@kaoru0822-kitauji commented on GitHub (Nov 2, 2026):

Re-ran the controlled case on main 8250bf232 (macOS arm64, real stdio MCP, unexecuted self-built stripped Mach-O, no Ghidra, Hopper, IDA or Kuna installed). The input hash was unchanged, and the results match the follow-up above.

Observed, with no usable deep provider:

Call Outcome Response bytes
open_binary, automatic Success. Target summary only, with no provider fact 293
binary_session analysis_provider_binding: null and four unavailable candidates (1,346 bytes of the total) 19,420
binary_overview, list_procedures provider_unavailable with four rejections 3,535 and 3,521
inspect_macho Success through native-macos 13,559
open_binary with provider_id: "ghidra", fresh server provider_unavailable, then open: false 3,437

CLI rea analyze has no separate open step and returned provider_unavailable directly.

Simulated, not the real TCC failure: I used the repo's tests/fixtures/hopperLaunchAdmission.mjs launcher, which reports the Apple Events denial. Automatic open_binary succeeded and bound Hopper (selection_source: "auto-single-candidate"). binary_overview and list_procedures then returned provider_unavailable at stage launch. From source, HopperProvider.inspectAvailability only checks that the launcher is an executable file.

If a real denial behaves the same way, the reported session was bound rather than unbound, so an unbound signal on open would not have flagged it. I have no real Hopper here and did not reproduce target_unavailable, so that case is still open.

Not opening a PR: what remains looks like a contract decision, not a bug. The registry treats an unbound target as intentional, and shallow inspection depends on it. Neither #8487 nor #8613 changes the result of a successful open.

Open question: should a successful open_binary state its binding, and how much of the reason? The sizes below are serialized-byte estimates for this four-provider case; nothing is implemented.

  1. No result change: the tool description says automatic open can succeed unbound, and binary_session stays the state query.
  2. Bound provider ID or null: the success counterpart of provider_id_at_open_completion in #8613, about 30 bytes.
  3. Option 2 plus each rejection's provider ID and code: about 280 bytes, with binary_session or the failed deep call still holding the reasons and remediation.

From source, a field inside result repeats across the 9 target-summary variants in the advertised output schema (4,613 bytes today).

<!-- gh-comment-id:6569961273 --> @kaoru0822-kitauji commented on GitHub (Nov 2, 2026): Re-ran the controlled case on main `8250bf232` (macOS arm64, real stdio MCP, unexecuted self-built stripped Mach-O, no Ghidra, Hopper, IDA or Kuna installed). The input hash was unchanged, and the results match the follow-up above. **Observed, with no usable deep provider:** | Call | Outcome | Response bytes | | --- | --- | --- | | `open_binary`, automatic | Success. Target summary only, with no provider fact | 293 | | `binary_session` | `analysis_provider_binding: null` and four unavailable candidates (1,346 bytes of the total) | 19,420 | | `binary_overview`, `list_procedures` | `provider_unavailable` with four rejections | 3,535 and 3,521 | | `inspect_macho` | Success through `native-macos` | 13,559 | | `open_binary` with `provider_id: "ghidra"`, fresh server | `provider_unavailable`, then `open: false` | 3,437 | CLI `rea analyze` has no separate open step and returned `provider_unavailable` directly. **Simulated, not the real TCC failure:** I used the repo's `tests/fixtures/hopperLaunchAdmission.mjs` launcher, which reports the Apple Events denial. Automatic `open_binary` succeeded and **bound** Hopper (`selection_source: "auto-single-candidate"`). `binary_overview` and `list_procedures` then returned `provider_unavailable` at stage `launch`. From source, `HopperProvider.inspectAvailability` only checks that the launcher is an executable file. If a real denial behaves the same way, the reported session was bound rather than unbound, so an unbound signal on open would not have flagged it. I have no real Hopper here and did not reproduce `target_unavailable`, so that case is still open. **Not opening a PR:** what remains looks like a contract decision, not a bug. The registry treats an unbound target as intentional, and shallow inspection depends on it. Neither #8487 nor #8613 changes the result of a successful open. **Open question:** should a successful `open_binary` state its binding, and how much of the reason? The sizes below are serialized-byte estimates for this four-provider case; nothing is implemented. 1. **No result change:** the tool description says automatic open can succeed unbound, and `binary_session` stays the state query. 2. **Bound provider ID or `null`:** the success counterpart of `provider_id_at_open_completion` in #8613, about 30 bytes. 3. **Option 2 plus each rejection's provider ID and code:** about 280 bytes, with `binary_session` or the failed deep call still holding the reasons and remediation. From source, a field inside `result` repeats across the 9 target-summary variants in the advertised output schema (4,613 bytes today).
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#6481
No description provided.