Skip to content

fix: lazy SQLite corruption recovery in MCP ToolHandler (Issue #679)#683

Merged
jununfly merged 1 commit into
mainfrom
fix/issue-679-malformed-recovery
Jul 13, 2026
Merged

fix: lazy SQLite corruption recovery in MCP ToolHandler (Issue #679)#683
jununfly merged 1 commit into
mainfrom
fix/issue-679-malformed-recovery

Conversation

@jununfly

Copy link
Copy Markdown
Owner

Issue

Fixes #679 — MCP server holds stale SQLite connection after CLI zcodegraph index rebuilds the database, causing database disk image is malformed errors.

Root Cause

CLI zcodegraph index rebuilds the .codegraph/codegraph.db file. The MCP server's long-lived CodeGraph instance still holds the old SQLite handle → stale → corruption error on next tool call.

Fix: Lazy Detection + Reopen + Retry (Option A)

  • Detect: isSqliteCorruptionError() matches malformed / SQLITE_CORRUPT / file is not a database
  • Reopen: CodeGraph.reopen() — public method, reuses existing reopenDatabaseAfterExternalIndex() logic
  • Retry: ToolHandler.execute() refactored to executeOnce() + retry wrapper; reopens DB and retries exactly once on corruption

TDD Vertical Slices

Slice Test Implementation
1-1 isSqliteCorruptionError matches 3 patterns, rejects non-corruption, handles non-Error src/db/error-detection.ts
1-2 CodeGraph.reopen() serves queries after reopen src/index.ts — public reopen()
1-3 ToolHandler retries on corruption, skips non-corruption, no double-retry src/mcp/tools.tsexecute() + executeOnce()

Files Changed

  • src/db/error-detection.ts — new: isSqliteCorruptionError(err: unknown): boolean
  • src/index.ts — new: CodeGraph.reopen() public method
  • src/mcp/tools.ts — refactored: execute()executeOnce() + retry wrapper
  • __tests__/malformed-recovery.test.ts — 9 TDD tests

Tests

npx vitest run __tests__/malformed-recovery.test.ts9/9 pass
npx vitest run __tests__/mcp-*.test.ts23/23 pass (no regression)

When CLI `zcodegraph index` rebuilds the database file, the MCP server's
long-lived CodeGraph instance holds a stale SQLite handle. Subsequent
tool calls fail with 'database disk image is malformed'.

Fix: detect corruption errors in ToolHandler.execute()'s catch block,
reopen the database connection via CodeGraph.reopen(), and retry the
tool call exactly once.

TDD vertical slices:
- isSqliteCorruptionError(): match malformed/SQLITE_CORRUPT/file is not a database
- CodeGraph.reopen(): public method, reuses existing reopenDatabaseAfterExternalIndex()
- ToolHandler.execute(): refactored to executeOnce() + retry wrapper
- 9 tests covering detection, reopen, retry success, non-corruption skip,
  and no-double-retry guard

Existing MCP tests: 23/23 pass (no regression).
@jununfly
jununfly merged commit 856a62d into main Jul 13, 2026
3 checks passed
@jununfly
jununfly deleted the fix/issue-679-malformed-recovery branch July 14, 2026 03:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

zcodegraph MCP returns malformed database after reindex

1 participant