Skip to content

cbm v0.8.1 silently deletes project DBs on "corrupt" detection — data loss with no recovery #557

Closed

Description

@jonlimx

Summary

codebase-memory-mcp v0.8.1 (and earlier) contains a deleting corrupt db code
path that silently unlinks the project database file when its startup
integrity check raises any anomaly. This is a "delete on first suspicion"
design that causes total data loss with no backup, no log warning, and no
recovery path — even when the "corruption" is a false positive.

Evidence

The behavior is in the compiled binary and observable via strings:

deleting corrupt db
ERROR store.corrupt table=projects rows=%d (expected 1)
ERROR store.corrupt table=projects bad_root_path=%s
integrity_check_failed
malformed database schema (%s)
file is not a database
broke stale lock on %s

Related binary paths (WAL mode + atomic rename used for normal writes):

PRAGMA journal_mode = WAL;
%s.tmp
dump: rename failed
rename_to_cache

Trigger conditions (false positives)

In my case the project DB was deleted after I performed a sequence of
pkill -9 on the cbm process and binary swaps between standard and ui
variants (the install.sh --ui switch). The next cbm startup detected
"corruption" and deleted the 28 MB <project>.db file. Other plausible
triggers I can think of:

  1. WAL file leftover from a previously-SIGKILL'd cbm (most likely in
    my case). When the old process is killed, SQLite's -wal and -shm
    sidecar files can be left in a state the new process interprets as
    corruption.
  2. Binary version drift between cbm builds (e.g., switching between
    codebase-memory-mcp-darwin-arm64.tar.gz and
    codebase-memory-mcp-ui-darwin-arm64.tar.gz). Even minor schema-version
    differences would trip the check.
  3. Lock-file contention — the broke stale lock on %s string shows cbm
    forcibly breaks stale locks; the DB state immediately after lock break
    may look anomalous and trigger the delete.

Repro

  1. codebase-memory-mcp cli index_repository '{"repo_path":"/path/to/proj","mode":"full"}'
  2. pkill -9 -f "codebase-memory-mcp" while index is in progress (or
    between operations)
  3. Start cbm again. The <proj>.db file disappears.
  4. No log line other than level=info msg=mem.init ... precedes the loss.

Impact

  • Total data loss of the indexed project (in my case: 8 740 nodes /
    26 412 edges / 28 MB SQLite, plus the graph.db.zst artifact)
  • No backup, no .corrupt.<timestamp> rename, no in-process log warning
  • User has no idea what happened until they re-open the UI and see
    "No indexed projects"
  • Recovery requires re-running the full reindex, which costs time
    (3-4 min for Linux kernel per the README, several minutes for any
    real codebase)

Suggested fix

Replace the unlink with a rename to a timestamped .corrupt file and
emit a prominent stderr log so the user has a chance to act:

// pseudocode for the recovery branch
if (integrity_check_fails) {
    char corrupt_path[PATH_MAX];
    snprintf(corrupt_path, sizeof(corrupt_path),
             "%s.corrupt.%ld", db_path, (long)time(NULL));
    rename(db_path, corrupt_path);
    fprintf(stderr,
        "ERROR project database marked corrupt: %s\n"
        "ERROR   preserved as: %s\n"
        "ERROR   re-index:  codebase-memory-mcp cli index_repository "
        "'{\"repo_path\":\"...\",\"mode\":\"full\"}'\n",
        db_path, corrupt_path);
}

This preserves the evidence, lets the user inspect what was wrong, and
gives them a recovery path (file a bug with the corrupt DB attached).

Environment

  • cbm 0.8.1 (binary --version and serverInfo.version both report 0.8.1;
    note: prior 0.6.1 release had a serverInfo.version: 0.10.0 mismatch
    per issue #350)
  • macOS 26.4.1, Darwin 25.4.0 arm64, Apple Silicon
  • Binary: Mach-O 64-bit executable arm64, 270.9 MB (UI variant)
  • Related: issue #350
    (UI HTTP server doesn't bind, closed) and
    issue #402
    (UI binary crashes mid-render, open) — both UI-related

Activity

  1. DeusData commented on Jun 23, 2026

    @DeusData
    Owner

    Thanks for the detailed write-up and the strings-level evidence — a delete-on-first-suspicion path with no backup and no recovery is not acceptable behavior, and I'm treating this as a data-loss bug (bug / stability/performance).

    Your WAL / -shm-leftover-after-SIGKILL theory is the most likely trigger; a schema-version mismatch from swapping between the standard and ui archives is also plausible. The fix direction here is to quarantine (rename the file aside) rather than unlink on a corruption signal, attempt WAL recovery first, and always log loudly before touching the file.

    Tracking this alongside the silent-corruption work in #391. If you still have the shell history around the deletion, the exact sequence would help me reproduce it.

  2. jonlimx commented on Jun 25, 2026

    @jonlimx
    Author

    I checked ~/.zsh_history (8051 entries, persisted by oh-my-zsh). The exact pkill -9 cbm and install.sh --ui sequence is not there — the only pkill in my history is sudo pkill -f qemu (unrelated), and the only cbm-related entries are wrapper commands I wrote (cbm-ui, cbm-ui-stop, cbm-status, cbm-info, cbm-full).

    The actual deletion sequence almost certainly ran through opencode's bash tool, which spawns ephemeral shells that do not write to ~/.zsh_history. So the "Repro" steps in the original report are a hypothesis (observed symptom + plausible cause), not a verified shell trace. Sorry for not flagging this when I filed the issue — I should have marked those steps as "best guess" rather than "repro".

    The most likely trigger is still the WAL/SHM-leftover theory: a pkill -9 of cbm mid-write leaves -wal / -shm sidecars that the next startup interprets as corruption. If you want a deterministic repro, the test case is probably:

    cbm-full /path/to/repo
    pkill -9 -f codebase-memory-mcp        # mid-index
    ls /path/to/repo/.cache/codebase-memory-mcp/Users-...db*  # shows -wal / -shm sidecars
    cbm-info /path/to/repo                 # next startup; expects: <db>.db disappears
    

    For PR #620: I'm happy to test the rename-on-corruption behavior once it lands. I have the v0.8.1 UI binary and a clean test repo I can use to reproduce the WAL-leftover path end-to-end.

  3. yasku commented on Jun 25, 2026

    @yasku

    I checked ~/.zsh_history (8051 entries, persisted by oh-my-zsh). The exact pkill -9 cbm and install.sh --ui sequence is not there — the only pkill in my history is sudo pkill -f qemu (unrelated), and the only cbm-related entries are wrapper commands I wrote (cbm-ui, cbm-ui-stop, cbm-status, cbm-info, cbm-full).

    The actual deletion sequence almost certainly ran through opencode's bash tool, which spawns ephemeral shells that do not write to ~/.zsh_history. So the "Repro" steps in the original report are a hypothesis (observed symptom + plausible cause), not a verified shell trace. Sorry for not flagging this when I filed the issue — I should have marked those steps as "best guess" rather than "repro".

    The most likely trigger is still the WAL/SHM-leftover theory: a pkill -9 of cbm mid-write leaves -wal / -shm sidecars that the next startup interprets as corruption. If you want a deterministic repro, the test case is probably:

    cbm-full /path/to/repo
    pkill -9 -f codebase-memory-mcp        # mid-index
    ls /path/to/repo/.cache/codebase-memory-mcp/Users-...db*  # shows -wal / -shm sidecars
    cbm-info /path/to/repo                 # next startup; expects: <db>.db disappears
    

    For PR #620: I'm happy to test the rename-on-corruption behavior once it lands. I have the v0.8.1 UI binary and a clean test repo I can use to reproduce the WAL-leftover path end-to-end.

    For sure! Let me know what u found as i got the same issue ... Right now it works clean, all testes passes but check it

  4. yasku commented on Jun 25, 2026

    @yasku

    Fully tested locally on MacOS tahoe 26. Gates pass ok, pr check pass okey. Hope it helps

  5. DeusData commented on Jun 28, 2026

    @DeusData
    Owner

    Reproduced in the cumulative bug-reproduction suite in #667 and fixed there: on a "corrupt" detection the project DB is now backed up instead of being silently deleted, so a false-positive corruption check can no longer destroy a user's index. The reproduction stays as a regression guard.

    (Lands when #667 merges.)

  6. added
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    on Jun 30, 2026
  7. added this to the 0.9.1-rc milestone on Jul 8, 2026
  8. DeusData commented on Sep 19, 2026

    @DeusData
    Owner

    Thank you for the report and for clarifying which trigger details were hypotheses. The destructive recovery path was changed in 639bac9 and subsequently hardened in 0e00ef5; both are included in v0.11.0. Current recovery publishes a verified recovery snapshot before removing the live database, and preserves the live generation if backup preparation fails. Closing the silent-deletion defect as fixed. This does not claim that every possible corruption trigger has been eliminated.

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/memory

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions