[GH-ISSUE #1979] [Bug] NE, LE and LX refusals give misleading "check the path" advice #659

Closed
opened 2026-10-15 18:27:02 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @CassieFox23 on GitHub (Oct 11, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1979

TL;DR: REA refuses NE files on purpose, and that's fine. But the error also says "Check that the path exists, is readable." The path is fine, so users and agents look in the wrong place. Only details.reason says the real cause.

Before submitting

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

#720 fixed the same kind of wording for JavaScript folders.

Area

Native analysis or decompilation

Observed behavior

open_binary on a 16-bit Windows NE file returns this:

{"error":{"code":"target_unavailable","category":"unavailable","message":"Cannot open artifact: unsupported NE executable in MZ image. Check that the path exists, is readable, and points to a supported file.","retryable":false,"remediation":{"action":"Cannot open artifact: unsupported NE executable in MZ image. Check that the path exists, is readable, and points to a supported file."},"details":{"path":"/tmp/ne-check/fixtures/ne/wzoom.exe","reason":"unsupported NE executable in MZ image"}}}
  • The file exists and is readable. The same folder's DOS MZ file opens fine.
  • The fix-it text just repeats the message. It gives no next step for a format REA refuses.
  • rea inspect --provider ghidra --json prints the same object and exits 1.
  • A user on the REA Discord read this kind of refusal as a model guardrail. It was REA's own check.

Reproduction

  1. Get binw/wzoom.exe from the Open Watcom v2 snapshot (release tag Current-build). It has MZ at 0 and NE at offset 0x80.
  2. Call open_binary with its path over MCP, or run rea inspect --provider ghidra --json <path>.
  3. Read message and remediation.action.

Expected behavior

Say the format is not supported, and drop the path advice for this case. For example: "NE executables are not supported. REA's DOS lane takes MZ and COM images only." The refusal itself is by design (docs/ghidra-dos.md).

Where it comes from

src/domain/analysisErrorPresentation.ts line 216 adds the path sentence to every BinaryTargetError, except directory_requires_file. The NE refusal comes from src/domain/binaryTarget.ts line 197. Both lines are the same on today's main, 55b61485e.

Impact and scope

Any refused format gets this text if REA raises it as a BinaryTargetError. I checked NE only. LE and LX share the same code line, but I did not run them.

Version and runtime

  • REA main 1449e8e05 (package 6.4.0), built from source
  • Node 24.18.0, Ghidra 12.1.4, JDK 21
  • Nobara 44 (Fedora 44 base), Linux 7.2.9

Target

Open Watcom v2 wzoom.exe (Sybase Open Watcom Public License 1.0), 33,502 bytes, sha256 0316c5acf8f13f1a618e7106de74db3ce1f844bfb4f259f2f8d5f041efe3175d. Ghidra 12.1.4 loads it directly, with its New Executable loader, as x86:LE:16:Protected Mode:default.

Earliest failure stage

When REA checks the file, before Ghidra starts.

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

Originally created by @CassieFox23 on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1979 **TL;DR:** REA refuses NE files on purpose, and that's fine. But the error also says "Check that the path exists, is readable." The path is fine, so users and agents look in the wrong place. Only `details.reason` says the real cause. ### 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. #720 fixed the same kind of wording for JavaScript folders. ### Area Native analysis or decompilation ### Observed behavior `open_binary` on a 16-bit Windows NE file returns this: ```json {"error":{"code":"target_unavailable","category":"unavailable","message":"Cannot open artifact: unsupported NE executable in MZ image. Check that the path exists, is readable, and points to a supported file.","retryable":false,"remediation":{"action":"Cannot open artifact: unsupported NE executable in MZ image. Check that the path exists, is readable, and points to a supported file."},"details":{"path":"/tmp/ne-check/fixtures/ne/wzoom.exe","reason":"unsupported NE executable in MZ image"}}} ``` - The file exists and is readable. The same folder's DOS MZ file opens fine. - The fix-it text just repeats the message. It gives no next step for a format REA refuses. - `rea inspect --provider ghidra --json` prints the same object and exits 1. - A user on the REA Discord read this kind of refusal as a model guardrail. It was REA's own check. ### Reproduction 1. Get `binw/wzoom.exe` from the Open Watcom v2 snapshot (release tag `Current-build`). It has `MZ` at 0 and `NE` at offset 0x80. 2. Call `open_binary` with its path over MCP, or run `rea inspect --provider ghidra --json <path>`. 3. Read `message` and `remediation.action`. ### Expected behavior Say the format is not supported, and drop the path advice for this case. For example: "NE executables are not supported. REA's DOS lane takes MZ and COM images only." The refusal itself is by design (`docs/ghidra-dos.md`). ### Where it comes from `src/domain/analysisErrorPresentation.ts` line 216 adds the path sentence to every `BinaryTargetError`, except `directory_requires_file`. The NE refusal comes from `src/domain/binaryTarget.ts` line 197. Both lines are the same on today's main, 55b61485e. ### Impact and scope Any refused format gets this text if REA raises it as a `BinaryTargetError`. I checked NE only. LE and LX share the same code line, but I did not run them. ### Version and runtime - REA main 1449e8e05 (package 6.4.0), built from source - Node 24.18.0, Ghidra 12.1.4, JDK 21 - Nobara 44 (Fedora 44 base), Linux 7.2.9 ### Target Open Watcom v2 `wzoom.exe` (Sybase Open Watcom Public License 1.0), 33,502 bytes, sha256 `0316c5acf8f13f1a618e7106de74db3ce1f844bfb4f259f2f8d5f041efe3175d`. Ghidra 12.1.4 loads it directly, with its New Executable loader, as `x86:LE:16:Protected Mode:default`. ### Earliest failure stage When REA checks the file, before Ghidra starts. 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
bsakaguchi 2026-10-15 18:27:02 +00:00
Author
Owner

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

A follow-up test is running now on Linux, on today's main (55b61485e):

  • LE and LX files from the same Open Watcom snapshot.
  • Other refused formats that may hit the same line 216. These include a plain text file and a cut-off header. It also covers ELF and PE files for a chip REA doesn't map.
  • A folder and a missing path, for contrast.

I expect to post the results by about 23:00 UTC. That time is a rough estimate.

🤖 Generated with Claude Code (Opus 5.5) 🦊

<!-- gh-comment-id:6114399801 --> @CassieFox23 commented on GitHub (Oct 11, 2026): A follow-up test is running now on Linux, on today's main (55b61485e): - LE and LX files from the same Open Watcom snapshot. - Other refused formats that may hit the same line 216. These include a plain text file and a cut-off header. It also covers ELF and PE files for a chip REA doesn't map. - A folder and a missing path, for contrast. I expect to post the results by about 23:00 UTC. That time is a rough estimate. 🤖 Generated with Claude Code (Opus 5.5) 🦊
Author
Owner

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

TL;DR: LE and LX files get the same wrong "check the path" text as NE. So do other refused files, like text files and ELF, PE and Mach-O files with an unmapped field. The fix should cover every format refusal, not just NE.

Results

All runs used REA main 55b61485e. Every refusal below returns code target_unavailable. The file exists and is readable in every row.

File Refusal reason (details.reason) Path advice in message and remediation.action CLI exit
NE wzoom.exe unsupported NE executable in MZ image yes 1
LE cwhelp.exe unsupported LE executable in MZ image yes 1
LX wcc.exe unsupported LX executable in MZ image yes 1
Plain text file unsupported binary format yes 1
4-byte file truncated or unsupported binary header yes 1
ELF, e_machine set to 243 unsupported ELF architecture yes 1
ELF, class byte set to 3 unsupported ELF class yes 1
ELF, endianness byte set to 3 unsupported ELF endianness yes 1
ELF cut to 40 bytes truncated ELF header: an ELF64 header needs 64 bytes; the file has 40 yes 1
PE, Machine set to 0x5032 unsupported PE architecture yes 1
Mach-O, unknown CPU type unsupported Mach-O architecture yes 1
70,000-byte file, format=dos-com (MCP only) DOS COM requires 1..65280 file bytes yes not run

I also called open_binary over MCP on eight of these. They were NE, LE, LX, the text file, the 4-byte file, the ELF architecture case, the PE architecture case and the DOS COM size case. Each returned isError: true with the path sentence in both message and remediation.action. The two fields are the same string in all eight.

Three cases are fine:

  • A directory gets its own text, with no path sentence. This is the directory_requires_file case.
  • A missing path gets the path sentence, and there it is right.
  • An unreadable file gets code access_denied and its own correct remediation.action. Its message also ends with the path sentence, which fits here.

So the sentence lands on every format refusal I ran. None of them is a path problem, and none skips it. Line 216 of src/domain/analysisErrorPresentation.ts and line 197 of src/domain/binaryTarget.ts are unchanged on 55b61485e.

Still not run

  • Real-world ELF, PE and Mach-O files. The ELF and PE cases are copies with one header field changed. The Mach-O case is a 32-byte header I built by hand.
  • A Mach-O refusal over MCP, and the dos-com case over the CLI.
  • The other Mach-O and FAT refusals in binaryTarget.ts.
  • raw-binary refusals.
  • The Hopper and IDA providers. I used --provider ghidra only.
  • Windows and macOS.

Edit: the four struck items are now covered in a follow-up comment.

rea doctor and rea capabilities say nothing about NE, LE or LX. docs/ghidra-dos.md does list them as unsupported.

Commands
# build (Node 24 first on PATH)
git -C <rea-mirror>/rea.git archive 55b61485e9f7568b69597eef8696ff6abfe53cfd | tar -x -C /tmp/i1979/rea
npm ci --prefix /tmp/i1979/rea && npm run build --prefix /tmp/i1979/rea

# fixtures: LE and LX files from the Open Watcom v2 snapshot
gh release download Current-build -R open-watcom/open-watcom-v2 -p ow-snapshot.tar.xz
tar -xJf ow-snapshot.tar.xz ./binw/cwhelp.exe ./binp/wcc.exe ./binw/wzoom.exe ./binnt/netserv.exe ./license.txt

# one run per file
node scripts/rea.mjs inspect --provider ghidra --json <file>     # exit code read each time

# MCP: initialize, then tools/call open_binary {"path": "<file>"} over stdio
node scripts/rea.mjs mcp
path in archive   size    sha256
binw/cwhelp.exe   17833   77adbc85a9a559128f2139ad6c6692a748bf89498330d1e0d597afd08faaceda   (LE)
binp/wcc.exe      18647   79a9c788b8f981fdec8507928a33b2dfde041e8e70038f3bda14585768144fd5   (LX)
binw/wzoom.exe    33502   0316c5acf8f13f1a618e7106de74db3ce1f844bfb4f259f2f8d5f041efe3175d   (NE)

I read the header of each file myself. All three have MZ at 0 and e_lfanew 0x80. The two bytes at 0x80 are LE, LX and NE. The PE copy came from binnt/netserv.exe with its Machine field changed from 0x14c to 0x5032. The ELF copies came from a small local ELF64 binary, with one header field changed each.

All three files come from the Open Watcom v2 snapshot. Its licence is the Sybase Open Watcom Public License 1.0 (SPDX Watcom-1.0). The release tag is Current-build. I read the licence name in license.txt at the archive root.

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
  • REA main: 55b61485e (package 6.4.0)
  • Other: Ghidra 12.1.4, JDK 21, Open Watcom v2 snapshot (Sybase Open Watcom Public License 1.0)

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

<!-- gh-comment-id:6114565781 --> @CassieFox23 commented on GitHub (Oct 11, 2026): **TL;DR:** LE and LX files get the same wrong "check the path" text as NE. So do other refused files, like text files and ELF, PE and Mach-O files with an unmapped field. The fix should cover every format refusal, not just NE. ### Results All runs used REA main 55b61485e. Every refusal below returns code `target_unavailable`. The file exists and is readable in every row. | File | Refusal reason (`details.reason`) | Path advice in `message` and `remediation.action` | CLI exit | |---|---|---|---| | NE `wzoom.exe` | unsupported NE executable in MZ image | yes | 1 | | LE `cwhelp.exe` | unsupported LE executable in MZ image | yes | 1 | | LX `wcc.exe` | unsupported LX executable in MZ image | yes | 1 | | Plain text file | unsupported binary format | yes | 1 | | 4-byte file | truncated or unsupported binary header | yes | 1 | | ELF, `e_machine` set to 243 | unsupported ELF architecture | yes | 1 | | ELF, class byte set to 3 | unsupported ELF class | yes | 1 | | ELF, endianness byte set to 3 | unsupported ELF endianness | yes | 1 | | ELF cut to 40 bytes | truncated ELF header: an ELF64 header needs 64 bytes; the file has 40 | yes | 1 | | PE, Machine set to 0x5032 | unsupported PE architecture | yes | 1 | | Mach-O, unknown CPU type | unsupported Mach-O architecture | yes | 1 | | 70,000-byte file, `format=dos-com` (MCP only) | DOS COM requires 1..65280 file bytes | yes | not run | I also called `open_binary` over MCP on eight of these. They were NE, LE, LX, the text file, the 4-byte file, the ELF architecture case, the PE architecture case and the DOS COM size case. Each returned `isError: true` with the path sentence in both `message` and `remediation.action`. The two fields are the same string in all eight. Three cases are fine: - **A directory** gets its own text, with no path sentence. This is the `directory_requires_file` case. - **A missing path** gets the path sentence, and there it is right. - **An unreadable file** gets code `access_denied` and its own correct `remediation.action`. Its `message` also ends with the path sentence, which fits here. So the sentence lands on every format refusal I ran. None of them is a path problem, and none skips it. Line 216 of `src/domain/analysisErrorPresentation.ts` and line 197 of `src/domain/binaryTarget.ts` are unchanged on 55b61485e. ### Still not run - ~~Real-world ELF, PE and Mach-O files. The ELF and PE cases are copies with one header field changed. The Mach-O case is a 32-byte header I built by hand.~~ - ~~A Mach-O refusal over MCP, and the dos-com case over the CLI.~~ - ~~The other Mach-O and FAT refusals in `binaryTarget.ts`.~~ - ~~`raw-binary` refusals.~~ - The Hopper and IDA providers. I used `--provider ghidra` only. - Windows and macOS. **Edit:** the four struck items are now covered in [a follow-up comment](https://github.com/morluto/rea/issues/1979#issuecomment-6114720623). `rea doctor` and `rea capabilities` say nothing about NE, LE or LX. `docs/ghidra-dos.md` does list them as unsupported. <details> <summary>Commands</summary> ```bash # build (Node 24 first on PATH) git -C <rea-mirror>/rea.git archive 55b61485e9f7568b69597eef8696ff6abfe53cfd | tar -x -C /tmp/i1979/rea npm ci --prefix /tmp/i1979/rea && npm run build --prefix /tmp/i1979/rea # fixtures: LE and LX files from the Open Watcom v2 snapshot gh release download Current-build -R open-watcom/open-watcom-v2 -p ow-snapshot.tar.xz tar -xJf ow-snapshot.tar.xz ./binw/cwhelp.exe ./binp/wcc.exe ./binw/wzoom.exe ./binnt/netserv.exe ./license.txt # one run per file node scripts/rea.mjs inspect --provider ghidra --json <file> # exit code read each time # MCP: initialize, then tools/call open_binary {"path": "<file>"} over stdio node scripts/rea.mjs mcp ``` ```text path in archive size sha256 binw/cwhelp.exe 17833 77adbc85a9a559128f2139ad6c6692a748bf89498330d1e0d597afd08faaceda (LE) binp/wcc.exe 18647 79a9c788b8f981fdec8507928a33b2dfde041e8e70038f3bda14585768144fd5 (LX) binw/wzoom.exe 33502 0316c5acf8f13f1a618e7106de74db3ce1f844bfb4f259f2f8d5f041efe3175d (NE) ``` I read the header of each file myself. All three have `MZ` at 0 and `e_lfanew` 0x80. The two bytes at 0x80 are `LE`, `LX` and `NE`. The PE copy came from `binnt/netserv.exe` with its Machine field changed from 0x14c to 0x5032. The ELF copies came from a small local ELF64 binary, with one header field changed each. All three files come from the Open Watcom v2 snapshot. Its licence is the Sybase Open Watcom Public License 1.0 (SPDX Watcom-1.0). The release tag is `Current-build`. I read the licence name in `license.txt` at the archive root. </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 - REA main: 55b61485e (package 6.4.0) - Other: Ghidra 12.1.4, JDK 21, Open Watcom v2 snapshot (Sybase Open Watcom Public License 1.0) </details> 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
Author
Owner

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

TL;DR: Real files get the same wrong "check the path" advice. That covers a RISC-V ELF, a RISC-V PE and a PowerPC Mach-O. Every Mach-O and FAT refusal I could reach gets it too, and so do the raw-binary refusals that are not schema errors.

What is new

Main moved from 55b61485e to 7285e1583 since my last comment. The three new commits do not touch src/domain/binaryTarget.ts or src/application/BinaryTargetResolver.ts. The path sentence is now on line 219 of src/domain/analysisErrorPresentation.ts, not line 216. New lines were added above it. NE and a text file still get the sentence on 7285e1583.

Results

All rows return code target_unavailable, except the schema rows. The file exists and is readable in every row. "Same" in the MCP column means open_binary gave the same text as the CLI, with the sentence in both message and remediation.action.

File Refusal reason (details.reason) Path sentence CLI exit MCP
A riscv64 ELF from a Debian package unsupported ELF architecture yes 1 same
A riscv64 PE from a Debian package unsupported PE architecture yes 1 same
A PowerPC Mach-O file from the rizin tests unsupported Mach-O architecture yes 1 same
Mach-O, 4 cut files short header (3 files); short load commands (1 file) yes 1 same
FAT, 7 built files bad table (3); no host slice (3); slice past the end (1) yes 1 same
Java class, 2 files I built bad FAT table (small file); no host slice (big file) yes 1 same for small file
dos-com, 70,000 and 0 bytes DOS COM needs 1..65280 file bytes yes 1 same
raw-binary, 5 that pass the schema unaligned entry (2); empty file (1); address too wide (2) yes 1 (2 of 5 run) same
raw-binary and dos-com, 12 schema cases input check message no not run isError, plain text

The ELF is true from Debian coreutils (GPL-3.0-or-later). The PE is systemd-boot from Debian (LGPL-2.1-or-later). The Mach-O is a rizin library (LGPL-3.0-only).

Three points stand out:

  • The sentence is wrong in the five raw-binary cases. The path is fine. The entry point or the file size is the problem.
  • Java class files start with the same four bytes as a FAT Mach-O file. REA reads them as FAT and refuses them with Mach-O wording. I compiled both classes myself with JDK 21.
  • CLI and MCP differ for raw-binary. With --target-format raw-binary and no --architecture, the CLI reaches the resolver and prints the sentence. Over MCP, the schema stops the same input first, with no sentence. An invalid --architecture mips on the CLI gives VALIDATION_ERROR, also with no sentence.
The 12 schema cases

The 12 schema cases:

  • raw-binary with no architecture and no entry point.
  • raw-binary with only an architecture.
  • raw-binary with only an entry point.
  • Architecture mips.
  • Entry point 1000, with no 0x.
  • Entry point 0x, with no digits.
  • An entry point with 17 digits.
  • An architecture with no format.
  • An entry point with no format.
  • dos-com with an architecture.
  • A format named elf.
  • A relative path.

Each one gives Input validation error: Invalid arguments for tool open_binary. None has the sentence.

Still not run

  • The Hopper and IDA providers. I used --provider ghidra only.
  • Windows and macOS.
  • Whether each refusal comes before Ghidra starts.
  • The "truncated FAT header" refusal on line 99 of src/domain/binaryTarget.ts. By reading the code, line 54 rejects anything under 8 bytes first, so it looks unreachable. I did not run it.
  • A FAT file with a host slice.
  • Real PE files for chips other than RISC-V 64.
Commands
# build (Node 24 first on PATH)
git -C <rea-mirror>/rea.git archive 7285e15839a4fecf9940683699b781a60ccc4775 | tar -x -C /tmp/i1979c/rea
npm ci --prefix /tmp/i1979c/rea && npm run build --prefix /tmp/i1979c/rea

# real files: Debian trixie riscv64 packages, extracted with ar and tar
ar x coreutils_9.7-3_riscv64.deb && tar -xJf data.tar.xz ./usr/bin/true
ar x systemd-boot-efi_257.13-1~deb13u1_riscv64.deb && tar -xJf data.tar.xz ./usr/lib/systemd/boot/efi/systemd-bootriscv64.efi

# one CLI run per file (exit code read each time)
node scripts/rea.mjs inspect --provider ghidra --json <file>
node scripts/rea.mjs inspect --provider ghidra --json --target-format dos-com <file>
node scripts/rea.mjs inspect --provider ghidra --json --target-format raw-binary --architecture arm --entry-point 0x1002 <file>

# MCP: initialize, then tools/call open_binary over stdio
node scripts/rea.mjs mcp
# arguments used, for example:
#   {"path": "<file>", "format": "raw-binary", "architecture": "arm", "entry_point": "0x1002"}
#   {"path": "<file>", "format": "dos-com"}
header facts I read myself
true (riscv64):            ELF class 2, little-endian, e_machine 243 (RISC-V)
systemd-bootriscv64.efi:   MZ, e_lfanew 0x40, PE signature, Machine 0x5064 (RISC-V 64)
librz_main.ppc32.dylib:    magic feedface, cputype 0x12 (PowerPC), filetype 6 (dylib)

The hand-made files, all in /tmp/i1979c/fx:

  • Mach-O: a 20-byte file with a 64-bit magic. A 24-byte file with a 32-bit magic. A 32-byte header that declares 4,096 bytes of load commands. A 7-byte file that starts with a Mach-O magic.
  • FAT, with magic cafebabe (and cafebabf for the 64-bit form): count 0. Count 129. Count 2 with one entry. One arm64 entry. One PowerPC entry. One x86_64 entry that ends at byte 104,096 in a 28-byte file. One FAT64 file with an arm64 entry.
  • raw-binary and dos-com used a 34-byte text file, a 0-byte file and a 70,000-byte file.
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
  • Head / base: 7285e1583 / 55b61485e (package 6.4.0)
  • Other: Ghidra 12.1.4, JDK 21.0.12.1 (used only to compile the two Java test classes).

Downloaded files, each with its licence beside it:

coreutils_9.7-3_riscv64.deb (GPL-3.0-or-later; one source file also BSD-4-Clause-UC)
  3036184 bytes, sha256 47b00d78d09c7921296f1b849cd04e5cdda7fd948abf17d8659efb906ac386d7
  https://deb.debian.org/debian/pool/main/c/coreutils/coreutils_9.7-3_riscv64.deb
  extracted usr/bin/true: 31208 bytes, sha256 19b6c4a17a7e33b1d6ac49b969f942fc772f076561e0c204773d3f4a26e92a27

systemd-boot-efi_257.13-1~deb13u1_riscv64.deb (LGPL-2.1-or-later)
  134032 bytes, sha256 a9a714e2449c896ee99874b800500a5584a229839080d5fb88f4a611a1b5c642
  https://deb.debian.org/debian/pool/main/s/systemd/systemd-boot-efi_257.13-1~deb13u1_riscv64.deb
  extracted systemd-bootriscv64.efi: 97280 bytes, sha256 a2b262b0fd925f2a85cbad799f5f3768bc2a775f4b353018d44301fb7bd8e3a6

librz_main.ppc32.dylib (rizin, LGPL-3.0-only)
  298492 bytes, sha256 1bfaeab72761d89b0c2acec1fda52b17dd521dad78aae0bf9f134b06226f2f48
  https://raw.githubusercontent.com/rizinorg/rizin-testbins/master/mach0/librz_main.ppc32.dylib

wzoom.exe, NE, from the Open Watcom v2 snapshot, reused from the first run (Watcom-1.0)

Both Debian sha256 values match the Debian trixie Packages.xz index. The Debian copyright files list GPL-3+ for coreutils and LGPL-2.1+ for systemd. The librz_main.ppc32.dylib strings name rizin library paths. The SPDX header of librz/main/rizin.c on rizin's main branch reads LGPL-3.0-only. This binary is a 2022 build from rizin 0.5, so I did not check the header of that exact source file. I did not check the licence of the test-files repository.

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

<!-- gh-comment-id:6114720623 --> @CassieFox23 commented on GitHub (Oct 11, 2026): **TL;DR:** Real files get the same wrong "check the path" advice. That covers a RISC-V ELF, a RISC-V PE and a PowerPC Mach-O. Every Mach-O and FAT refusal I could reach gets it too, and so do the `raw-binary` refusals that are not schema errors. ### What is new Main moved from 55b61485e to 7285e1583 since my last comment. The three new commits do not touch `src/domain/binaryTarget.ts` or `src/application/BinaryTargetResolver.ts`. The path sentence is now on line 219 of `src/domain/analysisErrorPresentation.ts`, not line 216. New lines were added above it. NE and a text file still get the sentence on 7285e1583. ### Results All rows return code `target_unavailable`, except the schema rows. The file exists and is readable in every row. "Same" in the MCP column means `open_binary` gave the same text as the CLI, with the sentence in both `message` and `remediation.action`. | File | Refusal reason (`details.reason`) | Path sentence | CLI exit | MCP | |---|---|---|---|---| | A riscv64 ELF from a Debian package | unsupported ELF architecture | yes | 1 | same | | A riscv64 PE from a Debian package | unsupported PE architecture | yes | 1 | same | | A PowerPC Mach-O file from the rizin tests | unsupported Mach-O architecture | yes | 1 | same | | Mach-O, 4 cut files | short header (3 files); short load commands (1 file) | yes | 1 | same | | FAT, 7 built files | bad table (3); no host slice (3); slice past the end (1) | yes | 1 | same | | Java class, 2 files I built | bad FAT table (small file); no host slice (big file) | yes | 1 | same for small file | | `dos-com`, 70,000 and 0 bytes | DOS COM needs 1..65280 file bytes | yes | 1 | same | | `raw-binary`, 5 that pass the schema | unaligned entry (2); empty file (1); address too wide (2) | yes | 1 (2 of 5 run) | same | | `raw-binary` and `dos-com`, 12 schema cases | input check message | no | not run | `isError`, plain text | The ELF is `true` from Debian coreutils (GPL-3.0-or-later). The PE is systemd-boot from Debian (LGPL-2.1-or-later). The Mach-O is a rizin library (LGPL-3.0-only). Three points stand out: - **The sentence is wrong in the five `raw-binary` cases.** The path is fine. The entry point or the file size is the problem. - **Java class files start with the same four bytes as a FAT Mach-O file.** REA reads them as FAT and refuses them with Mach-O wording. I compiled both classes myself with JDK 21. - **CLI and MCP differ for `raw-binary`.** With `--target-format raw-binary` and no `--architecture`, the CLI reaches the resolver and prints the sentence. Over MCP, the schema stops the same input first, with no sentence. An invalid `--architecture mips` on the CLI gives `VALIDATION_ERROR`, also with no sentence. <details> <summary>The 12 schema cases</summary> The 12 schema cases: - `raw-binary` with no architecture and no entry point. - `raw-binary` with only an architecture. - `raw-binary` with only an entry point. - Architecture `mips`. - Entry point `1000`, with no `0x`. - Entry point `0x`, with no digits. - An entry point with 17 digits. - An architecture with no format. - An entry point with no format. - `dos-com` with an architecture. - A format named `elf`. - A relative path. Each one gives `Input validation error: Invalid arguments for tool open_binary`. None has the sentence. </details> ### Still not run - The Hopper and IDA providers. I used `--provider ghidra` only. - Windows and macOS. - Whether each refusal comes before Ghidra starts. - The "truncated FAT header" refusal on line 99 of `src/domain/binaryTarget.ts`. By reading the code, line 54 rejects anything under 8 bytes first, so it looks unreachable. I did not run it. - A FAT file with a host slice. - Real PE files for chips other than RISC-V 64. <details> <summary>Commands</summary> ```bash # build (Node 24 first on PATH) git -C <rea-mirror>/rea.git archive 7285e15839a4fecf9940683699b781a60ccc4775 | tar -x -C /tmp/i1979c/rea npm ci --prefix /tmp/i1979c/rea && npm run build --prefix /tmp/i1979c/rea # real files: Debian trixie riscv64 packages, extracted with ar and tar ar x coreutils_9.7-3_riscv64.deb && tar -xJf data.tar.xz ./usr/bin/true ar x systemd-boot-efi_257.13-1~deb13u1_riscv64.deb && tar -xJf data.tar.xz ./usr/lib/systemd/boot/efi/systemd-bootriscv64.efi # one CLI run per file (exit code read each time) node scripts/rea.mjs inspect --provider ghidra --json <file> node scripts/rea.mjs inspect --provider ghidra --json --target-format dos-com <file> node scripts/rea.mjs inspect --provider ghidra --json --target-format raw-binary --architecture arm --entry-point 0x1002 <file> # MCP: initialize, then tools/call open_binary over stdio node scripts/rea.mjs mcp # arguments used, for example: # {"path": "<file>", "format": "raw-binary", "architecture": "arm", "entry_point": "0x1002"} # {"path": "<file>", "format": "dos-com"} ``` ```text header facts I read myself true (riscv64): ELF class 2, little-endian, e_machine 243 (RISC-V) systemd-bootriscv64.efi: MZ, e_lfanew 0x40, PE signature, Machine 0x5064 (RISC-V 64) librz_main.ppc32.dylib: magic feedface, cputype 0x12 (PowerPC), filetype 6 (dylib) ``` The hand-made files, all in `/tmp/i1979c/fx`: - Mach-O: a 20-byte file with a 64-bit magic. A 24-byte file with a 32-bit magic. A 32-byte header that declares 4,096 bytes of load commands. A 7-byte file that starts with a Mach-O magic. - FAT, with magic `cafebabe` (and `cafebabf` for the 64-bit form): count 0. Count 129. Count 2 with one entry. One `arm64` entry. One PowerPC entry. One `x86_64` entry that ends at byte 104,096 in a 28-byte file. One FAT64 file with an `arm64` entry. - `raw-binary` and `dos-com` used a 34-byte text file, a 0-byte file and a 70,000-byte file. </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 - Head / base: 7285e1583 / 55b61485e (package 6.4.0) - Other: Ghidra 12.1.4, JDK 21.0.12.1 (used only to compile the two Java test classes). Downloaded files, each with its licence beside it: ```text coreutils_9.7-3_riscv64.deb (GPL-3.0-or-later; one source file also BSD-4-Clause-UC) 3036184 bytes, sha256 47b00d78d09c7921296f1b849cd04e5cdda7fd948abf17d8659efb906ac386d7 https://deb.debian.org/debian/pool/main/c/coreutils/coreutils_9.7-3_riscv64.deb extracted usr/bin/true: 31208 bytes, sha256 19b6c4a17a7e33b1d6ac49b969f942fc772f076561e0c204773d3f4a26e92a27 systemd-boot-efi_257.13-1~deb13u1_riscv64.deb (LGPL-2.1-or-later) 134032 bytes, sha256 a9a714e2449c896ee99874b800500a5584a229839080d5fb88f4a611a1b5c642 https://deb.debian.org/debian/pool/main/s/systemd/systemd-boot-efi_257.13-1~deb13u1_riscv64.deb extracted systemd-bootriscv64.efi: 97280 bytes, sha256 a2b262b0fd925f2a85cbad799f5f3768bc2a775f4b353018d44301fb7bd8e3a6 librz_main.ppc32.dylib (rizin, LGPL-3.0-only) 298492 bytes, sha256 1bfaeab72761d89b0c2acec1fda52b17dd521dad78aae0bf9f134b06226f2f48 https://raw.githubusercontent.com/rizinorg/rizin-testbins/master/mach0/librz_main.ppc32.dylib wzoom.exe, NE, from the Open Watcom v2 snapshot, reused from the first run (Watcom-1.0) ``` Both Debian sha256 values match the Debian trixie `Packages.xz` index. The Debian copyright files list GPL-3+ for coreutils and LGPL-2.1+ for systemd. The `librz_main.ppc32.dylib` strings name rizin library paths. The SPDX header of `librz/main/rizin.c` on rizin's main branch reads LGPL-3.0-only. This binary is a 2022 build from rizin 0.5, so I did not check the header of that exact source file. I did not check the licence of the test-files repository. </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#659
No description provided.