Skip to content

Installing a fresh DB file leaves the old -wal/-shm behind — SQLite replays the stale WAL over the new file #897

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?

Three code paths install a brand-new DB file at a path where a previous DB generation lived, and none of them removes an existing <path>-wal / <path>-shm sidecar:

  1. the pipeline dump — cbm_gbuf_dump_to_sqlite → the custom page writer opens the final cache path with fopen(path, "wb");
  2. cbm_artifact_import — renames the imported file over the cache path (it cleans up the tmp file's sidecars, not the destination's);
  3. cbm_store_dump_to_file — whose comment asserts the old sidecars "become stale and get recreated by the next reader".

That assertion is wrong: SQLite decides whether to replay a WAL purely from the sidecar's own header/checksums, not from any tie to the main file. A leftover WAL from a crashed or never-closed previous session is therefore recovered on top of the freshly installed file at the next open, splicing old-generation pages into it — short indexes, btreeInitPage failures, or silently resurrected stale rows depending on which frames land. The full pipeline path has no pre-dump sidecar cleanup at all (the incremental path happens to unlink them first, so the two pipelines disagree).

Expected: any code path that installs a fresh DB file deletes the destination's -wal/-shm first.

Reproduction

  1. Open a store at <path>, insert a few hundred rows; while the connection is still open, copy the hot <path>-wal aside. Close cleanly (checkpoint removes the WAL).
  2. Restore the copied -wal next to <path> — simulating a crashed session's leftover.
  3. Rebuild <path> from scratch (re-index the project, or any of the three paths above).
  4. Open the DB: the stale WAL is replayed over the new file. PRAGMA quick_check fails and/or row counts show the previous generation's data.

Cascade

An independent producer of the same corruption class as #895 (torn fast export); like it, the damage is then hidden by #896 (scans swallow SQLITE_CORRUPT). Fourth companion issue (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