[GH-ISSUE #2822] [Bug] Windows: a selected file held open exclusively by another process is reported as a non-retryable execution failure #1006

Closed
opened 2026-10-15 18:30:17 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @pablodiazjorge on GitHub (Oct 13, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2822

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

On Windows, when another process holds the selected file open without read sharing, Node's read fails with EBUSY. inspect_sqlite_database reports it as a generic execution failure that tells the caller not to retry:

code: execution_failure   category: execution_failure   retryable: false
message: Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed.
details.diagnostics.reason: EBUSY: resource busy or locked, open '<temp>\exclusive.sqlite'

The unchanged request succeeds as soon as the other process closes the file, so both the retry guidance and the rea doctor hint are wrong for this case.

Reproduction

  1. Create any SQLite database, for example exclusive.sqlite.
  2. In another PowerShell window, hold it open without sharing: $f = [System.IO.File]::Open('<path>\exclusive.sqlite', 'Open', 'ReadWrite', 'None').
  3. Run rea inspect-sqlite-database <path>\exclusive.sqlite --json: the output above, exit code 1.
  4. Run $f.Close() and repeat step 3: it succeeds.

Expected behavior

A distinct outcome that says the selected file is in use by another process, marks the request as retryable once that process releases it, and suggests closing the owning application or inspecting a copy.

Impact and scope

Any caller on Windows that inspects a database an application keeps open without read sharing gets a misleading, non-retryable error. POSIX hosts rarely return EBUSY for regular file reads, so this is mostly a Windows problem.

The same misclassification likely applies beyond SQLite: about 22 providers map EACCES/EPERM on selected-file reads to AnalysisAccessDeniedError (for example src/sqlite/SqliteDatabaseFailures.ts, src/pcap/PcapSnapshot.ts, src/go/GoBinaryProvider.ts), and none maps EBUSY.

REA version

Source build of main at 117bd23dd.

Runtime and platform

Windows 11 x64 (10.0.26300), non-elevated, Node 24.18.0, local NTFS volume, Windows native addon built from the same commit.

Target and artifact context

A small benign SQLite database created for the test (rollback journal mode, one table).

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

See "Observed behavior". In src/sqlite/SqliteDatabaseFailures.ts, the artifact-read phase maps EACCES/EPERM to AnalysisAccessDeniedError and ENOENT/ENOTDIR to an input error; any other code, including EBUSY, falls through to ProviderAdapterError, which projects as execution_failure with retryable: false.

Typed outcome or recovery expected

An unavailable outcome with retryable: true and a remediation to close the owning process or inspect a copy, in line with how #2467 treats transient Windows sharing conflicts in REA's own runtime paths.

Analysis or suspected cause

EBUSY is not part of the selected-file read error mapping in any provider. Would you prefer a shared mapping for selected-file read errors, or a first PR that handles EBUSY in the SQLite provider only? I can do either.

Additional context

Found while verifying inspect_sqlite_database (#2271) on native Windows, which CI does not cover. Everything else I tried worked: paths with spaces and non-ASCII characters, a WAL left by a writer that exited without closing (WAL included in the result), a live writer, a read-only file and a 317-character path. A hot rollback journal was rejected with a clear message, and no run left rea-sqlite-database-* directories in %TEMP%. Two SQLite boundary tests that fail on Windows for test-only reasons are fixed in a separate PR.

Originally created by @pablodiazjorge on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2822 ### 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 On Windows, when another process holds the selected file open without read sharing, Node's read fails with `EBUSY`. `inspect_sqlite_database` reports it as a generic execution failure that tells the caller not to retry: ```text code: execution_failure category: execution_failure retryable: false message: Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed. details.diagnostics.reason: EBUSY: resource busy or locked, open '<temp>\exclusive.sqlite' ``` The unchanged request succeeds as soon as the other process closes the file, so both the retry guidance and the `rea doctor` hint are wrong for this case. ### Reproduction 1. Create any SQLite database, for example `exclusive.sqlite`. 2. In another PowerShell window, hold it open without sharing: `$f = [System.IO.File]::Open('<path>\exclusive.sqlite', 'Open', 'ReadWrite', 'None')`. 3. Run `rea inspect-sqlite-database <path>\exclusive.sqlite --json`: the output above, exit code 1. 4. Run `$f.Close()` and repeat step 3: it succeeds. ### Expected behavior A distinct outcome that says the selected file is in use by another process, marks the request as retryable once that process releases it, and suggests closing the owning application or inspecting a copy. ### Impact and scope Any caller on Windows that inspects a database an application keeps open without read sharing gets a misleading, non-retryable error. POSIX hosts rarely return `EBUSY` for regular file reads, so this is mostly a Windows problem. The same misclassification likely applies beyond SQLite: about 22 providers map `EACCES`/`EPERM` on selected-file reads to `AnalysisAccessDeniedError` (for example `src/sqlite/SqliteDatabaseFailures.ts`, `src/pcap/PcapSnapshot.ts`, `src/go/GoBinaryProvider.ts`), and none maps `EBUSY`. ### REA version Source build of `main` at `117bd23dd`. ### Runtime and platform Windows 11 x64 (10.0.26300), non-elevated, Node 24.18.0, local NTFS volume, Windows native addon built from the same commit. ### Target and artifact context A small benign SQLite database created for the test (rollback journal mode, one table). ### Interface CLI ### Earliest failure stage Transport or result projection ### Relevant output or evidence See "Observed behavior". In `src/sqlite/SqliteDatabaseFailures.ts`, the `artifact-read` phase maps `EACCES`/`EPERM` to `AnalysisAccessDeniedError` and `ENOENT`/`ENOTDIR` to an input error; any other `code`, including `EBUSY`, falls through to `ProviderAdapterError`, which projects as `execution_failure` with `retryable: false`. ### Typed outcome or recovery expected An `unavailable` outcome with `retryable: true` and a remediation to close the owning process or inspect a copy, in line with how #2467 treats transient Windows sharing conflicts in REA's own runtime paths. ### Analysis or suspected cause `EBUSY` is not part of the selected-file read error mapping in any provider. Would you prefer a shared mapping for selected-file read errors, or a first PR that handles `EBUSY` in the SQLite provider only? I can do either. ### Additional context Found while verifying `inspect_sqlite_database` (#2271) on native Windows, which CI does not cover. Everything else I tried worked: paths with spaces and non-ASCII characters, a WAL left by a writer that exited without closing (WAL included in the result), a live writer, a read-only file and a 317-character path. A hot rollback journal was rejected with a clear message, and no run left `rea-sqlite-database-*` directories in `%TEMP%`. Two SQLite boundary tests that fail on Windows for test-only reasons are fixed in a separate PR.
bsakaguchi 2026-10-15 18:30:17 +00:00
Author
Owner

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

Resolved on main by 664c669bd.

Selected SQLite database/WAL EBUSY failures are now retryable busy outcomes. The current check injects the boundary failure; no Windows exclusive-lock workload is claimed.

Rechecked on main b8510ee00 in the current focused run: 20 test files passed, 225 tests passed and one platform-dependent test skipped. Relevant regression coverage: tests/boundary/sqlite/sqliteDatabaseBusy.test.ts.

<!-- gh-comment-id:6174991574 --> @morluto commented on GitHub (Oct 14, 2026): Resolved on main by 664c669bd. Selected SQLite database/WAL EBUSY failures are now retryable busy outcomes. The current check injects the boundary failure; no Windows exclusive-lock workload is claimed. Rechecked on main b8510ee00 in the current focused run: 20 test files passed, 225 tests passed and one platform-dependent test skipped. Relevant regression coverage: tests/boundary/sqlite/sqliteDatabaseBusy.test.ts.
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#1006
No description provided.