[GH-ISSUE #7417] [Bug] rea analyze reports an absent selected Ghidra project as execution_failure without its configuration setting #4423

Closed
opened 2026-10-31 00:49:40 +00:00 by bsakaguchi · 0 comments
Owner

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

Before submitting

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

Area

Native analysis or decompilation

Observed behavior

With a supported native target and REA_GHIDRA_PROJECT_PATH pointing to a nonexistent .gpr marker, rea analyze exits 1 with execution_failure. The error retains ENOENT and the selected path, but omits details.settings and repeats the filesystem exception as remediation.action. An existing .gpr whose matching .rep directory is absent instead produces configuration_invalid, identifies REA_GHIDRA_PROJECT_PATH, and tells the caller where to correct it.

Reproduction

  1. Start in the baseline checkout with its built runtime and dependencies. These commands use an existing Homebrew openjdk@21 installation, create an empty temporary directory, and construct an installation-inspection fixture. The placeholder Ghidra executables are not analysis engines; this failure happens before either is launched.
export PATH="/opt/homebrew/opt/node@24/bin:$PATH"
export JAVA_HOME="$(brew --prefix openjdk@21)/libexec/openjdk.jdk/Contents/Home"
REA_ROOT="$PWD"
PROBE="$(mktemp -d)"
cd "$PROBE"
mkdir -p home project ghidra/support ghidra/Ghidra/Features/Decompiler/os/mac_arm_64
printf 'application.version=12.1.4\napplication.release.name=PUBLIC\napplication.java.min=21\napplication.java.max=\n' > ghidra/Ghidra/application.properties
printf '#!/bin/sh\nexit 0\n' > ghidra/support/analyzeHeadless
cp ghidra/support/analyzeHeadless ghidra/Ghidra/Features/Decompiler/os/mac_arm_64/decompile
chmod +x ghidra/support/analyzeHeadless ghidra/Ghidra/Features/Decompiler/os/mac_arm_64/decompile
lipo -thin arm64e /bin/ls -output target
export HOME="$PWD/home" GHIDRA_INSTALL_DIR="$PWD/ghidra"
export REA_GHIDRA_PROJECT_PATH="$PWD/missing/app.gpr"
  1. Analyze the target and print the relevant fields from the actual response.
node "$REA_ROOT/scripts/rea.mjs" analyze "$PWD/target" --provider ghidra --json > missing.json 2>&1
printf 'exit=%s\n' "$?"
python3 - <<'PYCODE'
import json
r=json.load(open('missing.json'))
print(json.dumps({'code':r['code'],'system_code':r['details']['diagnostics']['system_code'],'syscall':r['details']['diagnostics']['syscall'],'settings':r['details'].get('settings')}))
PYCODE

Observed output:

exit=1
{"code": "execution_failure", "system_code": "ENOENT", "syscall": "lstat", "settings": null}
  1. Compare with an existing marker and missing .rep directory.
: > project/app.gpr
export REA_GHIDRA_PROJECT_PATH="$PWD/project/app.gpr"
node "$REA_ROOT/scripts/rea.mjs" analyze "$PWD/target" --provider ghidra --json > missing-rep.json 2>&1
printf 'exit=%s\n' "$?"
python3 - <<'PYCODE'
import json
r=json.load(open('missing-rep.json'))
print(json.dumps({'code':r['code'],'setting':r['details']['settings'][0]['setting']}))
PYCODE

Observed output:

exit=1
{"code": "configuration_invalid", "setting": "REA_GHIDRA_PROJECT_PATH"}

The absent-marker failure reproduced in three of three CLI attempts across two separately created fixture layouts. The missing-.rep comparison produced configuration_invalid in two of two attempts. A real Java prerequisite probe ran; no Ghidra engine or target executable ran.

Expected behavior

An absent selected project marker should be rejected as invalid REA_GHIDRA_PROJECT_PATH configuration, with that setting identity and recovery advice to restore the project or correct the selection in the environment that starts REA. docs/installation.md, heading "Reuse an existing Ghidra project", requires an expanded local project marker and says, "The matching .rep directory must be present; restore .grez archives with Ghidra first." docs/design/limits-and-recovery.md, heading "Recovery text", requires: "Preserve the configuration failure and its setting identity". The comparison case already provides this classification for the same selected project setting.

Impact and scope

The observed result prevents the selected analysis and labels a missing configured project as an execution failure. Callers that distinguish configuration_invalid from execution_failure receive the wrong recovery category and no structured setting identity. The path and ENOENT remain visible, so a person can infer that the selected file needs attention. No successful analysis, data loss or modification of a caller database was observed. Natural occurrence frequency, other commands, MCP transport, other platforms and successful analysis after correcting the setting remain untested.

REA version

6.8.0 (source commit a905a71e31)

Runtime and platform

Node 24.22.1; macOS 27.0.1 arm64; existing 64-bit OpenJDK 21.0.12.1; fixture Ghidra installation metadata 12.1.4.

Target and artifact context

Thin arm64e Mach-O extracted from the system /bin/ls, read as an analysis target without execution; authored Ghidra installation placeholders and nonexistent selected project marker.

Interface

CLI

Earliest failure stage

Setup or provider admission

Relevant output or evidence

Observed missing-marker JSON has code execution_failure, category execution_failure, retryable false, details.operation resolve_analysis_profile, and details.diagnostics containing system_code ENOENT and syscall lstat. Its message and remediation.action are the same ENOENT text naming the selected missing/app.gpr path; details.settings is absent. The missing-.rep control has code configuration_invalid and category invalid_input, with details.settings[0].setting REA_GHIDRA_PROJECT_PATH and remediation asking the caller to correct that setting in the shell or MCP registration environment.

Source-only (not executed as an isolated unit): src/ghidra/GhidraProvider.ts:399 inspects the installation and src/ghidra/GhidraProvider.ts:430 invokes selected-project resolution for this admitted POSIX native executable. src/ghidra/GhidraProjectSnapshot.ts:179 performs the initial unhandled lstat; src/ghidra/GhidraProjectSnapshot.ts:74 validates the remaining pair with missing-entry mapping and configuration errors. src/ghidra/GhidraFileArtifacts.ts:61 owns the generic file-failure projection.

Typed outcome or recovery expected

Return configuration_invalid with details.settings naming REA_GHIDRA_PROJECT_PATH and a constraint describing the absent selected marker. Preserve the distinction between an invalid selection and physical filesystem failures such as permission errors.

Analysis or suspected cause

Source-derived: the initial exact-marker lookup in src/ghidra/GhidraProjectSnapshot.ts:179 does not catch an absent entry, so the configuration-specific failure immediately below it never runs for ENOENT. The same module already maps absent entries before validating the project pair at src/ghidra/GhidraProjectSnapshot.ts:74. The observed difference is consistent with the early exception escaping into the generic file-failure mapper.

Additional context

The independent doctor invocation exited 0 with healthy true and the fixture Ghidra provider available. This report does not request doctor to validate the selected project: docs/installation.md, heading "Check readiness for your task", defines providerInspections as host-level checks and states that a caller-supplied input is not guaranteed valid.

Related but distinct: #2147 remains open for real macOS reuse verification after the selection implementation landed; #3751 remains open for Windows and archive support. Neither reports this missing-marker error classification. The merged existing-project implementation is present in the tested baseline. The npm registry reports 6.8.0 as latest; the source revision above identifies the actual tested bytes.

Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7417 ### 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 Native analysis or decompilation ### Observed behavior With a supported native target and REA_GHIDRA_PROJECT_PATH pointing to a nonexistent .gpr marker, rea analyze exits 1 with execution_failure. The error retains ENOENT and the selected path, but omits details.settings and repeats the filesystem exception as remediation.action. An existing .gpr whose matching .rep directory is absent instead produces configuration_invalid, identifies REA_GHIDRA_PROJECT_PATH, and tells the caller where to correct it. ### Reproduction 1. Start in the baseline checkout with its built runtime and dependencies. These commands use an existing Homebrew openjdk@21 installation, create an empty temporary directory, and construct an installation-inspection fixture. The placeholder Ghidra executables are not analysis engines; this failure happens before either is launched. ```sh export PATH="/opt/homebrew/opt/node@24/bin:$PATH" export JAVA_HOME="$(brew --prefix openjdk@21)/libexec/openjdk.jdk/Contents/Home" REA_ROOT="$PWD" PROBE="$(mktemp -d)" cd "$PROBE" mkdir -p home project ghidra/support ghidra/Ghidra/Features/Decompiler/os/mac_arm_64 printf 'application.version=12.1.4\napplication.release.name=PUBLIC\napplication.java.min=21\napplication.java.max=\n' > ghidra/Ghidra/application.properties printf '#!/bin/sh\nexit 0\n' > ghidra/support/analyzeHeadless cp ghidra/support/analyzeHeadless ghidra/Ghidra/Features/Decompiler/os/mac_arm_64/decompile chmod +x ghidra/support/analyzeHeadless ghidra/Ghidra/Features/Decompiler/os/mac_arm_64/decompile lipo -thin arm64e /bin/ls -output target export HOME="$PWD/home" GHIDRA_INSTALL_DIR="$PWD/ghidra" export REA_GHIDRA_PROJECT_PATH="$PWD/missing/app.gpr" ``` 2. Analyze the target and print the relevant fields from the actual response. ```sh node "$REA_ROOT/scripts/rea.mjs" analyze "$PWD/target" --provider ghidra --json > missing.json 2>&1 printf 'exit=%s\n' "$?" python3 - <<'PYCODE' import json r=json.load(open('missing.json')) print(json.dumps({'code':r['code'],'system_code':r['details']['diagnostics']['system_code'],'syscall':r['details']['diagnostics']['syscall'],'settings':r['details'].get('settings')})) PYCODE ``` Observed output: ```text exit=1 {"code": "execution_failure", "system_code": "ENOENT", "syscall": "lstat", "settings": null} ``` 3. Compare with an existing marker and missing .rep directory. ```sh : > project/app.gpr export REA_GHIDRA_PROJECT_PATH="$PWD/project/app.gpr" node "$REA_ROOT/scripts/rea.mjs" analyze "$PWD/target" --provider ghidra --json > missing-rep.json 2>&1 printf 'exit=%s\n' "$?" python3 - <<'PYCODE' import json r=json.load(open('missing-rep.json')) print(json.dumps({'code':r['code'],'setting':r['details']['settings'][0]['setting']})) PYCODE ``` Observed output: ```text exit=1 {"code": "configuration_invalid", "setting": "REA_GHIDRA_PROJECT_PATH"} ``` The absent-marker failure reproduced in three of three CLI attempts across two separately created fixture layouts. The missing-.rep comparison produced configuration_invalid in two of two attempts. A real Java prerequisite probe ran; no Ghidra engine or target executable ran. ### Expected behavior An absent selected project marker should be rejected as invalid REA_GHIDRA_PROJECT_PATH configuration, with that setting identity and recovery advice to restore the project or correct the selection in the environment that starts REA. docs/installation.md, heading "Reuse an existing Ghidra project", requires an expanded local project marker and says, "The matching `.rep` directory must be present; restore `.grez` archives with Ghidra first." docs/design/limits-and-recovery.md, heading "Recovery text", requires: "Preserve the configuration failure and its setting identity". The comparison case already provides this classification for the same selected project setting. ### Impact and scope The observed result prevents the selected analysis and labels a missing configured project as an execution failure. Callers that distinguish configuration_invalid from execution_failure receive the wrong recovery category and no structured setting identity. The path and ENOENT remain visible, so a person can infer that the selected file needs attention. No successful analysis, data loss or modification of a caller database was observed. Natural occurrence frequency, other commands, MCP transport, other platforms and successful analysis after correcting the setting remain untested. ### REA version 6.8.0 (source commit a905a71e31f71457cb21fd056b234f872126974e) ### Runtime and platform Node 24.22.1; macOS 27.0.1 arm64; existing 64-bit OpenJDK 21.0.12.1; fixture Ghidra installation metadata 12.1.4. ### Target and artifact context Thin arm64e Mach-O extracted from the system /bin/ls, read as an analysis target without execution; authored Ghidra installation placeholders and nonexistent selected project marker. ### Interface CLI ### Earliest failure stage Setup or provider admission ### Relevant output or evidence Observed missing-marker JSON has code execution_failure, category execution_failure, retryable false, details.operation resolve_analysis_profile, and details.diagnostics containing system_code ENOENT and syscall lstat. Its message and remediation.action are the same ENOENT text naming the selected missing/app.gpr path; details.settings is absent. The missing-.rep control has code configuration_invalid and category invalid_input, with details.settings[0].setting REA_GHIDRA_PROJECT_PATH and remediation asking the caller to correct that setting in the shell or MCP registration environment. Source-only (not executed as an isolated unit): src/ghidra/GhidraProvider.ts:399 inspects the installation and src/ghidra/GhidraProvider.ts:430 invokes selected-project resolution for this admitted POSIX native executable. src/ghidra/GhidraProjectSnapshot.ts:179 performs the initial unhandled lstat; src/ghidra/GhidraProjectSnapshot.ts:74 validates the remaining pair with missing-entry mapping and configuration errors. src/ghidra/GhidraFileArtifacts.ts:61 owns the generic file-failure projection. ### Typed outcome or recovery expected Return configuration_invalid with details.settings naming REA_GHIDRA_PROJECT_PATH and a constraint describing the absent selected marker. Preserve the distinction between an invalid selection and physical filesystem failures such as permission errors. ### Analysis or suspected cause Source-derived: the initial exact-marker lookup in src/ghidra/GhidraProjectSnapshot.ts:179 does not catch an absent entry, so the configuration-specific failure immediately below it never runs for ENOENT. The same module already maps absent entries before validating the project pair at src/ghidra/GhidraProjectSnapshot.ts:74. The observed difference is consistent with the early exception escaping into the generic file-failure mapper. ### Additional context The independent doctor invocation exited 0 with healthy true and the fixture Ghidra provider available. This report does not request doctor to validate the selected project: docs/installation.md, heading "Check readiness for your task", defines providerInspections as host-level checks and states that a caller-supplied input is not guaranteed valid. Related but distinct: [#2147](https://github.com/morluto/rea/issues/2147) remains open for real macOS reuse verification after the selection implementation landed; [#3751](https://github.com/morluto/rea/issues/3751) remains open for Windows and archive support. Neither reports this missing-marker error classification. The merged existing-project implementation is present in the tested baseline. The npm registry reports 6.8.0 as latest; the source revision above identifies the actual tested bytes.
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#4423
No description provided.