Skip to content

Row-scan loops swallow SQLITE_CORRUPT — queries return plausible truncated/empty results with no error #896

Description

@kriswill

Version: codebase-memory-mcp 0.8.1 (built from source)
Platform: macOS (Apple Silicon) · Install channel: Built from source · Binary variant: standard

What happened, and what did you expect?

Every row-scan loop in the store layer has the shape while (sqlite3_step(stmt) == SQLITE_ROW) with the terminal code discarded, so SQLITE_CORRUPT mid-scan is indistinguishable from a clean end of results. Against a page-corrupted DB, counts are answered from covering indexes (correct) while row fetches die at the first corrupt table page (truncated/empty) — producing contradictory, error-free output across every query surface:

  • search_graph label mode: {"total": 379, "results": [], "has_more": true}
  • query_graph MATCH (n:Function) RETURN count(n) → 64, while get_graph_schema reports 379 Function nodes
  • some labels unreachable entirely via Cypher (zero rows even for count()) while the schema reports dozens of nodes
  • BM25 query= search: total: 0 despite matching symbols (corrupt FTS shadow tree)
  • get_architecture with path=: correct scoped_total_nodes, but node_labels: [], edge_types: [], scoped_total_edges: 0
  • search_code: grep matches present, graph enrichment total_results: 0

Expected: a loud "database is corrupted — re-index" error instead of plausible wrong answers. Silent truncation cost weeks of confusion in the field: the symptoms read as extraction/marshaling bugs and indexing blind spots, when the store data was simply unreadable.

Reproduction

Any public repo (e.g. colinhacks/zod), released binary + sqlite3 + dd only:

codebase-memory-mcp cli index_repository --repo-path /tmp/zod --mode full

# corrupt three mid-file pages of the cache DB (simulates a torn artifact — see #895)
DB=~/.cache/codebase-memory-mcp/<project>.db
PS=$(sqlite3 "$DB" 'PRAGMA page_size;'); PC=$(sqlite3 "$DB" 'PRAGMA page_count;')
dd if=/dev/zero of="$DB" bs=$PS seek=$((PC/2)) count=3 conv=notrunc

codebase-memory-mcp cli get_graph_schema --project <project>        # full label counts (index-covered)
codebase-memory-mcp cli query_graph --query 'MATCH (n:Function) RETURN count(n)' --project <project>   # truncated count, no error
codebase-memory-mcp cli search_graph --label Function --limit 5 --project <project>  # total=N, results=[], no error

Project scale (field occurrence)

3,977 nodes / 6,666 edges / ~480 files

Cascade

This is the concealer: it let the torn artifact from #895 serve wrong answers indefinitely. Filed alongside two related same-class issues (stale-WAL replay on DB swap; malformed-JSON emission), linked in a comment once created.

Maintainer note

I have a working private fix for this (with reproduce-first regression tests) that I can submit as a PR. Before I do, I'd prefer you groom this issue — confirm the framing, tag, and prioritize — so the PR lands against an agreed shape.

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions