Summary
When two or more Claude Code sessions point at the same project (same cache dir), codebase-memory-mcp crashes with SIGBUS on macOS arm64. The crash is 100% reproducible when opening 2+ windows on the same project.
Crash signature
EXC_BAD_ACCESS (SIGBUS)
Exception Codes: 0x000000000000000a, 0x0000000106038000
...
Termination Reason: Namespace SIGNAL, Code 10 Bus error: 10
...
FS pagein error: 22 Invalid argument cluster_pagein past EOF
...
Thread 0 Crashed:
sqlite3BtreeNext + ...
sqlite3VdbeSorterNext + ...
The kernel triage is always cluster_pagein past EOF — the mmap'd SQLite region is being accessed after the file has been truncated by another process.
Root cause (two independent layers)
Layer 1 — mmap + truncation:
configure_pragmas() hard-codes PRAGMA mmap_size = 67108864 on every connection (src/store/store.c:326). When process A's checkpoint or reindex truncates the DB while process B has it mmap'd, the next page fault in B's mmap region raises SIGBUS — an unrecoverable signal. If mmap were disabled (PRAGMA mmap_size = 0), the same truncation would produce recoverable SQLITE_IOERR instead.
Layer 2 — checkpoint mode:
cbm_store_checkpoint() uses SQLITE_CHECKPOINT_TRUNCATE (src/store/store.c:793). TRUNCATE is the most aggressive checkpoint mode — it calls ftruncate(fd, 0) on the WAL file on success. The SQLite docs recommend SQLITE_CHECKPOINT_PASSIVE for shared databases precisely because TRUNCATE can shrink files under concurrent readers.
Fixes
Two independent, low-risk fixes that each address one layer:
-
Expose mmap_size via CBM_SQLITE_MMAP_SIZE env — users sharing a cache dir can set CBM_SQLITE_MMAP_SIZE=0 to opt out of mmap without any behavior change for single-instance users. Default unchanged at 67108864.
-
Use PASSIVE checkpoint — switches cbm_store_checkpoint() from SQLITE_CHECKPOINT_TRUNCATE to SQLITE_CHECKPOINT_PASSIVE. PASSIVE never blocks readers and never calls ftruncate(). SQLite still autocheckpoints at 1000-page boundaries; disk reclamation is unaffected for single-process users.
PRs for both fixes are open:
fix/mmap-env-knob — feat(store): expose mmap_size via CBM_SQLITE_MMAP_SIZE env
fix/passive-checkpoint — fix(store): use PASSIVE checkpoint to avoid file-shrink under concurrent readers
Environment
- macOS 15 Sequoia, Apple Silicon (arm64)
- codebase-memory-mcp v0.6.0
- Claude Code with multiple windows, all using the same
claude mcp add codebase-memory-mcp config
Summary
When two or more Claude Code sessions point at the same project (same cache dir),
codebase-memory-mcpcrashes withSIGBUSon macOS arm64. The crash is 100% reproducible when opening 2+ windows on the same project.Crash signature
The kernel triage is always
cluster_pagein past EOF— the mmap'd SQLite region is being accessed after the file has been truncated by another process.Root cause (two independent layers)
Layer 1 — mmap + truncation:
configure_pragmas()hard-codesPRAGMA mmap_size = 67108864on every connection (src/store/store.c:326). When process A's checkpoint or reindex truncates the DB while process B has it mmap'd, the next page fault in B's mmap region raisesSIGBUS— an unrecoverable signal. If mmap were disabled (PRAGMA mmap_size = 0), the same truncation would produce recoverableSQLITE_IOERRinstead.Layer 2 — checkpoint mode:
cbm_store_checkpoint()usesSQLITE_CHECKPOINT_TRUNCATE(src/store/store.c:793). TRUNCATE is the most aggressive checkpoint mode — it callsftruncate(fd, 0)on the WAL file on success. The SQLite docs recommendSQLITE_CHECKPOINT_PASSIVEfor shared databases precisely because TRUNCATE can shrink files under concurrent readers.Fixes
Two independent, low-risk fixes that each address one layer:
Expose mmap_size via
CBM_SQLITE_MMAP_SIZEenv — users sharing a cache dir can setCBM_SQLITE_MMAP_SIZE=0to opt out of mmap without any behavior change for single-instance users. Default unchanged at 67108864.Use PASSIVE checkpoint — switches
cbm_store_checkpoint()fromSQLITE_CHECKPOINT_TRUNCATEtoSQLITE_CHECKPOINT_PASSIVE. PASSIVE never blocks readers and never callsftruncate(). SQLite still autocheckpoints at 1000-page boundaries; disk reclamation is unaffected for single-process users.PRs for both fixes are open:
fix/mmap-env-knob— feat(store): expose mmap_size via CBM_SQLITE_MMAP_SIZE envfix/passive-checkpoint— fix(store): use PASSIVE checkpoint to avoid file-shrink under concurrent readersEnvironment
claude mcp add codebase-memory-mcpconfig