Skip to content

Healthy project db silently quarantined to .corrupt and replaced with near-empty graph during concurrent CLI + multi-session MCP access (likely #391 family; correction in comments) #1037

Closed

Description

@putchi

Environment

  • Version: codebase-memory-mcp 0.9.0 (confirmed latest via codebase-memory-mcp update -n)
  • Platform: macOS (Apple Silicon) — macOS 26.5.2, Darwin arm64
  • Install channel: GitHub release archive / install.sh
  • Binary variant: ui (ui_enabled: true, binary ~273 MB)

What happened, and what did you expect?

A routine index_repository call on an already-indexed, healthy project silently discarded the existing graph and replaced it with a near-empty one — with status: "indexed" reported as success both times, no error, no warning.

Sequence:

  1. Project was previously indexed: 8,559 nodes / 25,407 edges, index_status reported status: "ready".
  2. Ran index_repository (mode: "fast") with no other activity in between — no kill signal, no binary swap, no relative path, no artifact export, no restart. Output reported success with the correct pre-existing counts (8,559 / 25,407) in that call's own log line.
  3. Immediately after, the on-disk <project>.db was found renamed to <project>.db.corrupt (preserved, not deleted — this is an improvement over the unlink behavior in cbm v0.8.1 silently deletes project DBs on "corrupt" detection — data loss with no recovery #557, so the rename-on-corruption fix appears at least partially shipped). A new, near-empty <project>.db had been created in its place.
  4. Subsequent searches against the "healthy" project now only see the new database. index_status on it reported 20 nodes / 19 edges.
  5. Ran index_repository again (mode: "fast") on the small db — reported success, grew to a still-catastrophically-small graph.
  6. Ran index_repository with mode: "full" explicitly, hoping for a clean rebuild — reported success, 784 nodes / 1,445 edges. Still nowhere near the original 8,559 / 25,407, despite the source repository being fully present and unchanged on disk (only two files had actually been edited since the last real index: a markdown doc and a config file — no source code changed).
  7. Recovered by manually renaming <project>.db.corrupt back over the fresh <project>.db — index_status immediately reported the correct 8,559 / 25,407 again, confirming the original backup was structurally intact and just needed restoring.

Expected: index_repository on an already-indexed project with a small, non-code-affecting diff should either (a) do an incremental update preserving the existing graph, or (b) if it decides a full rebuild is warranted, actually rebuild the complete graph rather than silently producing a 90%+ smaller one while still reporting status: "indexed" / success.

Possible new clue: SQLite writer-version mismatch between the "corrupt" file and the fresh one

$ file <project>.db.corrupt
SQLite 3.x database, last written using SQLite version 3046000, page size 1,
file counter 1, database pages 356, cookie 0x1, schema 4, UTF-8, version-valid-for 1

$ file <project>.db   # the fresh, near-empty replacement
SQLite 3.x database, last written using SQLite version 3051003, page size 1,
writer version 2, read version 2, file counter 3, database pages 68, cookie 0x6,
schema 4, UTF-8, version-valid-for 3

3046000 = SQLite 3.46.0, 3051003 = SQLite 3.51.3. The "corrupt" file was last written by a meaningfully older SQLite than the one the current codebase-memory-mcp binary links against. My guess: the original index was built by an earlier cbm release (before an update/reinstall bumped the bundled SQLite), and the current binary's integrity check treats that older on-disk format as corrupt on first touch, quarantines it, and silently starts fresh — landing squarely in the pattern #391 is tracking, but via a normal index_repository call with no crash/kill involved, which doesn't match any of the currently-listed sub-issues' trigger conditions.

Reproduction

I was not able to produce this from scratch on a synthetic/public repo — the trigger appears to require an index built by an older cbm binary version than the one currently installed, which isn't something I can fabricate without actually having an older release on hand to build the initial index. Happy to attempt this if a maintainer can point me at which older release/commit would be useful to install first (e.g. a build linking SQLite 3.46.x), or if CBM_DIAGNOSTICS=1 output from a re-trigger would help — I'd rather not re-run this against my own project again without guidance since it destroyed the graph the first time and I've already restored from the .corrupt backup.

What I can confirm reproduced twice in a row, deterministically, on my actual project:

  1. codebase-memory-mcp cli index_repository --repo-path <path> --mode fast on an already-indexed project → graph collapses to a fraction of its size, status: "indexed" still reported.
  2. Repeating the same command against the now-small db → still small, still reports success.
  3. --mode full on the now-small db → does not recover the original scale (784 vs. 8,559 nodes), despite the actual source tree being fully present and almost entirely unchanged.

Project shape (can't share the repository itself — private business codebase): TypeScript monorepo, 5 services (Next.js frontend, 2 Node backend services, a Python service, a shared package), several hundred source files.

Logs

level=info msg=mem.init budget_mb=11468 total_ram_mb=32768
level=info msg=index.supervisor.reap outcome=clean exit_code=0 signal=0
{"project":"<redacted>","excluded":{"dirs":[...],"count":54,"truncated":true},"skipped_count":0,"nodes":8559,"edges":25407,...,"status":"indexed"}

No warning, error, or corruption-related log line preceded or accompanied the collapse — only the same mem.init / index.supervisor.reap outcome=clean exit_code=0 lines seen on every normal run. The .corrupt rename happened silently between calls.

Project scale (if relevant)

8,559 nodes / 25,407 edges → 20 nodes / 19 edges → 784 nodes / 1,445 edges (recovered to 8,559 / 25,407 by manually restoring the .corrupt backup)

Confirmations

Activity

  1. putchi commented on Jul 12, 2026

    @putchi
    Author

    Correction after deeper investigation — original analysis partially wrong

    I re-tested everything with a byte-identical backup in hand. Two claims in the original report don't survive verification, and the corrected picture points somewhere more useful. Keeping the original text above for the record.

    Retracted: the SQLite version-mismatch theory

    Wrong. After restoring the quarantined .corrupt file (SQLite 3.46.0-era header) over the fresh db, the current 0.9.0 binary read and incrementally wrote that same file without any problem: it indexed ~170 new nodes from a recent merge onto it, the header now reads last written using SQLite version 3051003, and PRAGMA integrity_check returns ok. A subsequent explicit index_repository --mode fast on it also completed cleanly, preserving the full graph (8,728 nodes / 25,981 edges). The version difference in the header was provenance (file last written by an older binary), not the corruption trigger.

    Retracted: "deterministically reproduced twice" and "source unchanged"

    Also wrong, on re-examination of timestamps:

    • The --mode full run that produced only 784 nodes ran in the same minute a git pull --ff-only was rewriting the working tree (a concurrent agent session merged a PR and pulled; git reflog and file mtimes line up exactly). A full index racing a checkout that's rewriting hundreds of files plausibly explains a fraction-sized-but-"successful" result. The "source unchanged" claim in the original report was incorrect.
    • The intermediate 20-node reading was most likely a mid-rebuild snapshot, not a stable end state.
    • A controlled re-test (repo quiet, no concurrent pull, same already-indexed old-format db): index_repository --mode fast completed cleanly, no quarantine, graph fully preserved, integrity ok. So this is not deterministic.

    What still stands, and the corrected suspicion

    The original quarantine event is real and unexplained: a healthy 8,559-node db was renamed to .corrupt and silently replaced with a near-empty one during a burst of CLI invocations (--version, two detect_changes, a hook-augment, then index_repository, all within ~a minute) — while ~6 long-lived MCP stdio server processes (multiple concurrent agent sessions) held the same db open in WAL mode. No error or warning was emitted at any point; the run that coincided with the quarantine reported status: "indexed" with the pre-quarantine node counts.

    That profile — concurrent CLI writers + long-lived stdio servers on one WAL db, silent quarantine, success reported — reads like another datapoint for the #391 umbrella (nearest neighbors #557, #794, #896) rather than a new root cause. Feel free to fold this into #391 if that's the better home.

    Two things from this incident that may still be independently useful:

    1. Rename-to-.corrupt works and saved the data — the quarantined file was fully intact; renaming it back over the fresh db restored everything instantly, and the binary has been reading/writing it happily since. Whatever integrity check fired was a false positive at that moment. (This is the recovery behavior cbm v0.8.1 silently deletes project DBs on "corrupt" detection — data loss with no recovery #557 asks for — it shipped, and it works.)
    2. Query tools performing incremental sync are silent writers: I verified search_graph updates file_hashes for files modified since the last index. That means every concurrent agent session's queries are writers on the shared db, which widens the concurrent-writer surface well beyond explicit index_repository calls — possibly relevant to why these WAL races keep surfacing across task: Silent index corruption / incomplete index reported as success (3 issues) #391's sub-issues.

    Corrected environment note

    Multiple concurrent Claude Code sessions, each with its own cbm stdio MCP server attached to the same project db (6 processes at the time of corruption), plus CLI invocations from hooks. Single machine, macOS arm64, cbm 0.9.0 ui variant.

  2. changed the title [-]index_repository silently collapses an already-indexed graph to a fraction of its size — no crash/kill involved (SQLite version-mismatch trigger?)[/-] [+]Healthy project db silently quarantined to .corrupt and replaced with near-empty graph during concurrent CLI + multi-session MCP access (likely #391 family; correction in comments)[/+] on Jul 12, 2026
  3. added
    bugSomething isn't working
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    on Jul 14, 2026
  4. added this to the 0.9.1-rc milestone on Jul 14, 2026
  5. DeusData commented on Jul 14, 2026

    @DeusData
    Owner

    Thanks for correcting the initial theory after controlled retesting. The remaining concurrent-writer and false-positive quarantine behavior is still a high-priority 0.9.1-rc bug under the #391 family: a healthy database must not be silently displaced while success is reported. Investigation should focus on writer coordination, integrity-check timing, explicit quarantine diagnostics, and fail-closed recovery.

  6. added a commit that references this issue on Aug 11, 2026
  7. DeusData commented on Aug 11, 2026

    @DeusData
    Owner

    Fixed on main by @LynxBay's #1545 (merge afa6aeb) — shipping in v0.10.3.

    Your case was the other half of the same defect: a database whose projects table was intact but whose node/edge btrees were torn passed the shallow integrity check, so the damage went unnoticed rather than being caught. The quarantine path now also runs PRAGMA quick_check, which detects page-level damage — and, conversely, transient lock errors no longer masquerade as corruption, so healthy databases stop being quarantined by mistake.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.stability/performanceServer crashes, OOM, hangs, high CPU/memoryux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions