Repository navigation
Description
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:
- Project was previously indexed: 8,559 nodes / 25,407 edges,
index_statusreportedstatus: "ready". - 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. - Immediately after, the on-disk
<project>.dbwas found renamed to<project>.db.corrupt(preserved, not deleted — this is an improvement over theunlinkbehavior 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>.dbhad been created in its place. - Subsequent searches against the "healthy" project now only see the new database.
index_statuson it reported 20 nodes / 19 edges. - Ran
index_repositoryagain (mode: "fast") on the small db — reported success, grew to a still-catastrophically-small graph. - Ran
index_repositorywithmode: "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). - Recovered by manually renaming
<project>.db.corruptback over the fresh<project>.db—index_statusimmediately 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:
codebase-memory-mcp cli index_repository --repo-path <path> --mode faston an already-indexed project → graph collapses to a fraction of its size,status: "indexed"still reported.- Repeating the same command against the now-small db → still small, still reports success.
--mode fullon 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
- I searched existing issues and this is not a duplicate — related to the task: Silent index corruption / incomplete index reported as success (3 issues) #391 umbrella and cbm v0.8.1 silently deletes project DBs on "corrupt" detection — data loss with no recovery #557 specifically, but the trigger (plain
index_repositoryon a healthy already-indexed project, no kill/restart/relative-path/artifact-export involved) doesn't match any currently-listed sub-issue, so filing separately per the existing triage pattern. - My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code. Cannot confirm — see the Reproduction section for why, and what I'd need to produce one.
Activity
putchi commentedon Jul 12, 2026
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
.corruptfile (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 readslast written using SQLite version 3051003, andPRAGMA integrity_checkreturnsok. A subsequent explicitindex_repository --mode faston 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:
--mode fullrun that produced only 784 nodes ran in the same minute agit pull --ff-onlywas rewriting the working tree (a concurrent agent session merged a PR and pulled;git reflogand 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.index_repository --mode fastcompleted 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
.corruptand silently replaced with a near-empty one during a burst of CLI invocations (--version, twodetect_changes, ahook-augment, thenindex_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 reportedstatus: "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:
.corruptworks 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.)search_graphupdatesfile_hashesfor 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 explicitindex_repositorycalls — 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.
[-]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)[/+]DeusData commentedon Jul 14, 2026
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.
fix(store): distinguish transient SQLITE_BUSY from corruption before …
Merge pull request #1545 from LynxBay/fix/integrity-check-quarantine
DeusData commentedon Aug 11, 2026
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
projectstable 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 runsPRAGMA 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.test(store): bind the quarantine verdict that #1545 introduced (#1206, …
test(store): bind the quarantine verdict that #1545 introduced (#1206, …