[GH-ISSUE #4188] [Bug] SQLite path-resolution errors are reported as execution failures #1641

Closed
opened 2026-10-16 21:08:18 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Observed behavior

inspect-sqlite-database reports an initially unresolvable selected path as execution_failure, with no argument issue and guidance to run rea doctor. A directory-component symlink cycle and a 300-character path component both reproduce this result. Missing-file and non-directory controls instead return invalid_request / invalid_input with an issue on ["path"] and reason invalid_value. The invalid selections are correctly rejected; the defect is the typed classification and correction guidance.

Reproduction

Use the built source revision below. Set REA_ENTRYPOINT to the absolute path of its scripts/rea.mjs, then run this executed fixture in a separate empty working directory. It creates every input locally, including a valid database for the recovery control. Run without shell errexit, so the expected nonzero commands do not stop the controls.

mkdir sqlite-path-repro
cd sqlite-path-repro
mkdir home runtime
export HOME="$PWD/home"
export XDG_CONFIG_HOME="$PWD/home"
export TMPDIR="$PWD/runtime"
ln -s b a
ln -s a b
printf 'ordinary file' > plain-file
python3 - <<'PYFIXTURE'
import sqlite3
connection = sqlite3.connect("valid.db")
connection.execute("CREATE TABLE marker(value TEXT)")
connection.execute("INSERT INTO marker VALUES ('retained')")
connection.commit()
connection.close()
PYFIXTURE
node "$REA_ENTRYPOINT" inspect-sqlite-database a/x.db --json
printf 'loop exit: %s\n' "$?"
long_component=$(python3 -c "print('a' * 300)")
node "$REA_ENTRYPOINT" inspect-sqlite-database "$long_component/x.db" --json
printf 'long component exit: %s\n' "$?"
node "$REA_ENTRYPOINT" inspect-sqlite-database absent.db --json
printf 'missing exit: %s\n' "$?"
node "$REA_ENTRYPOINT" inspect-sqlite-database plain-file/x.db --json
printf 'non-directory exit: %s\n' "$?"
node "$REA_ENTRYPOINT" inspect-sqlite-database valid.db --json
printf 'valid exit: %s\n' "$?"

The observed exit statuses are 1, 1, 1, 1, 0. The loop and long-component requests return execution_failure; missing and non-directory requests return invalid_request / invalid_input with path / invalid_value; the valid database returns schema Evidence containing marker. Independent verifier, parent and final review CLI replays agreed on the cases each executed. This does not establish frequency on other environments.

The same five selections were executed through the production stdio MCP server started with node "$REA_ENTRYPOINT" mcp, using inspect_sqlite_database and each fixture's absolute host path in arguments.path. The two resolution failures returned isError: true with the same error inside the text content's { "error": ... } envelope. Both invalid-input controls and valid inspection matched the CLI outcomes. Final review repeated these real MCP calls.

Expected behavior

An initial inability to resolve the caller-selected SQLite file-set path should return the existing caller-input outcome: code: "invalid_request", category: "invalid_input", correction guidance, and a details.issues entry identifying ["path"] with reason: "invalid_value". SQLite's failure mapper explicitly preserves caller failure meanings and already gives initial ENOENT / ENOTDIR that outcome. Snapshot acquisition separately treats absence as a caller value to correct. These fixtures fail initial path resolution before parsing or worker execution; neither establishes a provider configuration failure or an identity change after acquisition.

Impact and scope

P2, supported: category-driven callers receive an execution failure and lose structured argument correction metadata for two bounded initial path-resolution errors. Both invalid inputs remain refused, and valid inspection succeeds. No data loss, general outage or downstream client incident was observed.

A practical workaround is available: inspect details.diagnostics.reason, correct the selected path, and supply an existing regular database. The valid control succeeded through CLI and MCP without changing REA. Other platforms, other errno cases and effects on specific external clients were not tested.

REA version

Source-built checkout at 62bf09809ef7bb224028916424f8f07652a20f4f. The source CLI reports 6.5.0; the published package was not reproduced. Current public main was fetched before submission, and relevant SQLite implementation, adapters, contracts, error taxonomy and documentation are unchanged. Current-main applicability is source-inspected, not a separate current-main runtime reproduction.

Runtime and platform

Node.js v24.18.0; npm 11.16.0; macOS arm64. The verifier and final review independently rebuilt the source runtime with npm run build:cached. The valid inspection reports SQLite 3.53.1. Calls used isolated HOME, XDG and temporary runtime directories. No external analysis provider or service was involved.

Target and artifact context

Locally generated path strings, a directory-component two-link cycle, an ordinary non-directory file, and a quiescent SQLite database with one marker(value TEXT) table. The failing selections cannot resolve to a database and never reach SQLite parsing.

Interface

CLI and MCP

Earliest failure stage

Capture or observation. The OS error arises during initial file-set observation and is then projected into the wrong typed outcome.

Relevant output or evidence

The two failing selections returned these fields through both interfaces. This excerpt omits path-bearing diagnostics.

{
  "code": "execution_failure",
  "category": "execution_failure",
  "message": "Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.",
  "retryable": false,
  "remediation": {
    "action": "Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed."
  }
}

Complete responses also contain details.provider_id: "sqlite", details.operation: "inspect_sqlite_database" and details.diagnostics.phase: "artifact-read", but no details.issues. The diagnostic reason begins with ELOOP: too many symbolic links encountered or ENAMETOOLONG: name too long. Concurrent initial database/WAL/journal stats mean that the OS diagnostic may name the selected database or a sibling path.

The existing focused command npm run test:focused -- tests/boundary/sqlite/sqliteDatabaseProvider.test.ts tests/acceptance/sqliteDatabaseCli.test.ts passed both files in the independent verifier run, with 30 passed and one unavailable-runtime case skipped on the supported runtime. Those tests do not cover the two reproduced errors. No full suite was run for this report.

Typed outcome or recovery expected

Proposed closure check: repeat the same initial-path fixtures through CLI and MCP. Both must remain rejected while returning invalid_request / invalid_input, an issue on path with invalid_value, and guidance to correct the argument. Keep missing and non-directory controls unchanged and retain successful valid inspection. Preserve permission-denial outcomes and artifact_changed for a file that changes after initial observation; this report does not request reclassification of every later ELOOP.

Analysis or suspected cause

Source-derived: initial file-set observation calls optionalStat, which suppresses only ENOENT. Initial ELOOP and ENAMETOOLONG reach the failure mapper but do not match its caller-path cases, so they fall through to ProviderAdapterError. The shared error projection maps that type to execution_failure and maps AnalysisInputError to invalid_request. This explains the observed output without prescribing an implementation.

Additional context

Closed #2614 distinguishes an absent database from malformed content; those absence controls now pass while these two initial resolution errors still fall through. Closed #2822 concerns a retryable Windows file-sharing conflict, not a caller-selected path that cannot resolve. Open #4127 concerns an over-budget input becoming an input error instead of a resource constraint. Open #3324 returns successful Evidence from the wrong database after symlink-parent normalization; no database is read in these failing cases. Their triggers and closure checks differ. NOT_ENOUGH_INFO: no last-known-good release or installed-package reproduction was established.

Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4188 ### 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 Evidence, artifacts, or reconstruction ### Observed behavior `inspect-sqlite-database` reports an initially unresolvable selected path as `execution_failure`, with no argument issue and guidance to run `rea doctor`. A directory-component symlink cycle and a 300-character path component both reproduce this result. Missing-file and non-directory controls instead return `invalid_request` / `invalid_input` with an issue on `["path"]` and reason `invalid_value`. The invalid selections are correctly rejected; the defect is the typed classification and correction guidance. ### Reproduction Use the built source revision below. Set `REA_ENTRYPOINT` to the absolute path of its `scripts/rea.mjs`, then run this executed fixture in a separate empty working directory. It creates every input locally, including a valid database for the recovery control. Run without shell `errexit`, so the expected nonzero commands do not stop the controls. ```sh mkdir sqlite-path-repro cd sqlite-path-repro mkdir home runtime export HOME="$PWD/home" export XDG_CONFIG_HOME="$PWD/home" export TMPDIR="$PWD/runtime" ln -s b a ln -s a b printf 'ordinary file' > plain-file python3 - <<'PYFIXTURE' import sqlite3 connection = sqlite3.connect("valid.db") connection.execute("CREATE TABLE marker(value TEXT)") connection.execute("INSERT INTO marker VALUES ('retained')") connection.commit() connection.close() PYFIXTURE node "$REA_ENTRYPOINT" inspect-sqlite-database a/x.db --json printf 'loop exit: %s\n' "$?" long_component=$(python3 -c "print('a' * 300)") node "$REA_ENTRYPOINT" inspect-sqlite-database "$long_component/x.db" --json printf 'long component exit: %s\n' "$?" node "$REA_ENTRYPOINT" inspect-sqlite-database absent.db --json printf 'missing exit: %s\n' "$?" node "$REA_ENTRYPOINT" inspect-sqlite-database plain-file/x.db --json printf 'non-directory exit: %s\n' "$?" node "$REA_ENTRYPOINT" inspect-sqlite-database valid.db --json printf 'valid exit: %s\n' "$?" ``` The observed exit statuses are `1, 1, 1, 1, 0`. The loop and long-component requests return `execution_failure`; missing and non-directory requests return `invalid_request` / `invalid_input` with `path` / `invalid_value`; the valid database returns schema Evidence containing `marker`. Independent verifier, parent and final review CLI replays agreed on the cases each executed. This does not establish frequency on other environments. The same five selections were executed through the production stdio MCP server started with `node "$REA_ENTRYPOINT" mcp`, using `inspect_sqlite_database` and each fixture's absolute host path in `arguments.path`. The two resolution failures returned `isError: true` with the same error inside the text content's `{ "error": ... }` envelope. Both invalid-input controls and valid inspection matched the CLI outcomes. Final review repeated these real MCP calls. ### Expected behavior An initial inability to resolve the caller-selected SQLite file-set path should return the existing caller-input outcome: `code: "invalid_request"`, `category: "invalid_input"`, correction guidance, and a `details.issues` entry identifying `["path"]` with `reason: "invalid_value"`. SQLite's [failure mapper](https://github.com/morluto/rea/blob/c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb/src/sqlite/SqliteDatabaseFailures.ts#L42-L137) explicitly preserves caller failure meanings and already gives initial `ENOENT` / `ENOTDIR` that outcome. [Snapshot acquisition](https://github.com/morluto/rea/blob/c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb/src/sqlite/SqliteDatabaseSnapshot.ts#L168-L200) separately treats absence as a caller value to correct. These fixtures fail initial path resolution before parsing or worker execution; neither establishes a provider configuration failure or an identity change after acquisition. ### Impact and scope P2, supported: category-driven callers receive an execution failure and lose structured argument correction metadata for two bounded initial path-resolution errors. Both invalid inputs remain refused, and valid inspection succeeds. No data loss, general outage or downstream client incident was observed. A practical workaround is available: inspect `details.diagnostics.reason`, correct the selected path, and supply an existing regular database. The valid control succeeded through CLI and MCP without changing REA. Other platforms, other errno cases and effects on specific external clients were not tested. ### REA version Source-built checkout at [62bf09809ef7bb224028916424f8f07652a20f4f](https://github.com/morluto/rea/commit/62bf09809ef7bb224028916424f8f07652a20f4f). The source CLI reports `6.5.0`; the published package was not reproduced. Current public main was fetched before submission, and relevant SQLite implementation, adapters, contracts, error taxonomy and documentation are unchanged. Current-main applicability is source-inspected, not a separate current-main runtime reproduction. ### Runtime and platform Node.js v24.18.0; npm 11.16.0; macOS arm64. The verifier and final review independently rebuilt the source runtime with `npm run build:cached`. The valid inspection reports SQLite 3.53.1. Calls used isolated HOME, XDG and temporary runtime directories. No external analysis provider or service was involved. ### Target and artifact context Locally generated path strings, a directory-component two-link cycle, an ordinary non-directory file, and a quiescent SQLite database with one `marker(value TEXT)` table. The failing selections cannot resolve to a database and never reach SQLite parsing. ### Interface CLI and MCP ### Earliest failure stage Capture or observation. The OS error arises during initial file-set observation and is then projected into the wrong typed outcome. ### Relevant output or evidence The two failing selections returned these fields through both interfaces. This excerpt omits path-bearing diagnostics. ```json { "code": "execution_failure", "category": "execution_failure", "message": "Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.", "retryable": false, "remediation": { "action": "Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed." } } ``` Complete responses also contain `details.provider_id: "sqlite"`, `details.operation: "inspect_sqlite_database"` and `details.diagnostics.phase: "artifact-read"`, but no `details.issues`. The diagnostic reason begins with `ELOOP: too many symbolic links encountered` or `ENAMETOOLONG: name too long`. Concurrent initial database/WAL/journal stats mean that the OS diagnostic may name the selected database or a sibling path. The existing focused command `npm run test:focused -- tests/boundary/sqlite/sqliteDatabaseProvider.test.ts tests/acceptance/sqliteDatabaseCli.test.ts` passed both files in the independent verifier run, with 30 passed and one unavailable-runtime case skipped on the supported runtime. Those tests do not cover the two reproduced errors. No full suite was run for this report. ### Typed outcome or recovery expected Proposed closure check: repeat the same initial-path fixtures through CLI and MCP. Both must remain rejected while returning `invalid_request` / `invalid_input`, an issue on `path` with `invalid_value`, and guidance to correct the argument. Keep missing and non-directory controls unchanged and retain successful valid inspection. Preserve permission-denial outcomes and `artifact_changed` for a file that changes after initial observation; this report does not request reclassification of every later ELOOP. ### Analysis or suspected cause Source-derived: initial file-set observation calls `optionalStat`, which suppresses only `ENOENT`. Initial `ELOOP` and `ENAMETOOLONG` reach the failure mapper but do not match its caller-path cases, so they fall through to `ProviderAdapterError`. The shared [error projection](https://github.com/morluto/rea/blob/c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb/src/domain/analysisErrorProjection.ts#L193-L217) maps that type to `execution_failure` and maps `AnalysisInputError` to `invalid_request`. This explains the observed output without prescribing an implementation. ### Additional context Closed [#2614](https://github.com/morluto/rea/issues/2614) distinguishes an absent database from malformed content; those absence controls now pass while these two initial resolution errors still fall through. Closed [#2822](https://github.com/morluto/rea/issues/2822) concerns a retryable Windows file-sharing conflict, not a caller-selected path that cannot resolve. Open [#4127](https://github.com/morluto/rea/issues/4127) concerns an over-budget input becoming an input error instead of a resource constraint. Open [#3324](https://github.com/morluto/rea/issues/3324) returns successful Evidence from the wrong database after symlink-parent normalization; no database is read in these failing cases. Their triggers and closure checks differ. NOT_ENOUGH_INFO: no last-known-good release or installed-package reproduction was established.
Author
Owner

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

Fixed on main in bc51d0ea5. Initial selected-path ELOOP and ENAMETOOLONG now match the existing invalid_request/path/invalid_value semantics through both compiled CLI and real stdio MCP. Acquisition-time failures remain artifact_changed. A valid long database name whose generated sidecar cannot be addressed is a distinct capability refusal, with no assumption that the sidecar is absent.

The public path, long-name, source-preservation and acquisition-race checks passed. Closing the reported classification defect.

Implementation qualification passed: CI at d9aa06d93. This verifies the implementation revision; the later PCAP-only batch has its own checks.

<!-- gh-comment-id:6201318255 --> @morluto commented on GitHub (Oct 15, 2026): Fixed on main in bc51d0ea5. Initial selected-path ELOOP and ENAMETOOLONG now match the existing invalid_request/path/invalid_value semantics through both compiled CLI and real stdio MCP. Acquisition-time failures remain artifact_changed. A valid long database name whose generated sidecar cannot be addressed is a distinct capability refusal, with no assumption that the sidecar is absent. The public path, long-name, source-preservation and acquisition-race checks passed. Closing the reported classification defect. Implementation qualification passed: [CI at d9aa06d93](https://github.com/morluto/rea/actions/runs/38797211865). This verifies the implementation revision; the later PCAP-only batch has its own checks.
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#1641
No description provided.