Root cause: createDatabase() caught everything the node:sqlite connection
threw and reported it as "CodeGraph requires node:sqlite (Node.js 22.5+)",
though the module had loaded and SQLite itself had failed: a database
another program held open (SQLITE_CANTOPEN on Windows), a folder the user
can't write, an I/O error on a network share. Failures in the connection's
first statements (locked, not a database, a WAL I/O error) came out raw,
without the path. The MCP server then told the agent "No CodeGraph project
is loaded" for a default project whose index exists, or "Tool execution
failed: ... requires node:sqlite" for a projectPath one. Meanwhile a runtime
that really lacks node:sqlite never got the hint: isInitialized's schema
probe loaded the module outside its try, so the CLI and MCP server died with
"Unhandled rejection: No such built-in module: node:sqlite".
Fix:
- src/db/node-sqlite.ts loads node:sqlite in one place;
NodeSqliteUnavailableError carries the Node 22.5+ hint, now only for a
module that cannot be loaded. The schema probe treats it as "unknown", so
the command goes on to the open and reports it from inside its own catch.
- src/db/open-error.ts: DatabaseOpenError names SQLite's code and the path,
with a hint for BUSY, PERM, READONLY, IOERR (network share), CORRUPT,
FULL, CANTOPEN (folder, permissions, another program holding the file)
and NOTADB, keeping code/errcode/errstr and the cause. The Windows/WSL
shared-index guidance still wins for its case.
- DatabaseConnection.open/initialize wrap the connection's first statements
as well as the constructor, and close the connection on failure.
- MCP: the default project's open failure is reported to a tool call instead
of "no project loaded", and a DatabaseOpenError or a missing node:sqlite
is answered isError with the retry-once note (a malfunction, per
AGENTS.md), worded as what failed rather than "an internal codegraph
error". Not-indexed projects keep their success-shaped guidance.
Validation:
- Windows, an indexed project whose codegraph.db another process holds open
with no sharing (a real SQLITE_CANTOPEN): CLI status, sync and query, an
MCP default-project call and a projectPath call all said "requires
node:sqlite" on main, or "No CodeGraph project is loaded" for the default
project; with the fix all name SQLITE_CANTOPEN, the path and the hint.
With --no-experimental-sqlite (node:sqlite unloadable), main's CLI and MCP
server died with an unhandled rejection; the fix prints the Node 22.5+
explanation and the MCP call answers with it.
- New __tests__/sqlite-open-error.test.ts (21 cases): main's source 18 fail
/ 3 pass, fix 21 pass. Real CANTOPEN (a directory, a file held
exclusively), NOTADB and BUSY opens, the CLI and the MCP engine, plus
each SQLite code's message. 5 mutations each failed at least one case.
- The POSIX-only wsl-shared-index case for a real I/O error outside WSL now
expects the named error (DatabaseOpenError, SQLITE_IOERR, the path) instead
of the bare "disk I/O error"; it is skipped on Windows, so it was not run
here.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>