Repository navigation
fix(sqlite): report a selected database held by another process as retryable - #2911
pablodiazjorge wants to merge 5 commits into
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b0e26710b4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5f6760beed
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| return new AnalysisCapabilityUnavailableError( | ||
| SQLITE_PROVIDER_IDENTITY.id, | ||
| operation, | ||
| `Selected database file set is in use by another process (EBUSY): ${path}`, |
There was a problem hiding this comment.
Preserve the actual busy file-set member
When EBUSY comes from opening <path>-wal or <path>-journal (both are read by captureSqliteDatabaseSnapshot), sqliteDatabaseFailure still receives the caller's base database path and this reason substitutes it for the filesystem error's cause.path. The projected diagnostic therefore drops which member was actually locked, making it impossible to distinguish a busy database from a busy sidecar; preserve a validated cause.path here and fall back to the selected path when it is absent.
AGENTS.md reference: AGENTS.md:L13-L13
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 23057bf: the reason now names the member of the file set that EBUSY reports (the database, its WAL or its journal), validated against those three paths, with a test for a busy WAL.
|
CI-fix track: this change is already on main. Merging current main into this branch yields a tree identical to main. Both |
|
Thanks @pablodiazjorge for distinguishing a temporarily locked SQLite database from malformed input. Main now reports the selected database as retryable while the competing process holds it (main). |
Summary
Fixes #2822 for the SQLite provider. On Windows, when another process holds the selected database open without read sharing, the read fails with
EBUSYandinspect_sqlite_databasereported a genericexecution_failurewithretryable: false, telling the caller to runrea doctorand not to retry. The same request succeeds once the other process releases the file.Problem and expected behavior
Smallest trigger, on Windows: hold a database with
[System.IO.File]::Open('<path>', 'Open', 'ReadWrite', 'None')and runrea inspect-sqlite-database <path> --json. Before this change:code: execution_failure,retryable: false. Expected: a retryable outcome that says the file is in use and how to recover.Change and scope
src/sqlite/SqliteDatabaseFailures.ts: in the artifact-read phase,EBUSYnow maps toAnalysisCapabilityUnavailableErrorwithretryable: true, next to the existingEACCES/EPERMandENOENT/ENOTDIRmappings. It projects ascapability_unavailable, categoryunavailable, with a message to close the owning application or inspect a copy, anddetails.reasonkeeps the path andEBUSY. This is the same retryableunavailableroute that fix(windows): preserve transient runtime admission failures #2467 uses for transient Windows sharing conflicts.tests/boundary/sqlite/sqliteDatabaseBusy.test.ts: a portable test that injects theEBUSYopen failure and checks the projection and that no private root is left, and a Windows-only test where a PowerShell process holds the file without sharing.Scope: SQLite only. As #2822 notes, about 22 providers map
EACCES/EPERMon selected-file reads and none mapsEBUSY; a shared mapping is left for your decision there.Contribution scope: not applicable (error classification within an existing provider).
Contract and boundary impact
execution_failureto the existingcapability_unavailablewithretryable: true.EBUSYfor regular files.docs/public/product-catalog.json), package, or installation impact: none.Evidence and regression coverage
tests/boundary/sqlite/sqliteDatabaseBusy.test.ts(2 tests).code: execution_failure; the real Windows case is in [Bug] Windows: a selected file held open exclusively by another process is reported as a non-retryable execution failure #2822.{"code":"capability_unavailable","category":"unavailable","retryable":true,"message":"The selected SQLite database is held open by another process without read sharing. Close that application or inspect a copy, then retry.", ...}Validation performed
Windows 11 x64 (10.0.26300), non-elevated, Node 24.18.0, Windows native addon built from the same commit.
npx vitest run tests/boundary/sqlite/sqliteDatabaseBusy.test.tson1b6c899b0: 2 passed; without the change, both fail withcode: execution_failure.npm run check:fast: passed.npx oxfmt --checkon the two files: passed.Compatibility, safety, and release
retryable: truenow retry this case.Before merge
type(scope): outcome.