[Bug] Bun: live ContentStore/SessionDB handle wedges to permanent SQLITE_IOERR (disk I/O error) on healthy disk+DB; ctx_doctor stays green
Summary
Under Claude Code on the Bun runtime, a single context-mode MCP server process can get wedged: every live ctx_search / ctx_index / ctx_fetch_and_index returns SQLITE_IOERR ("disk I/O error"), reads and writes alike, and stays that way for the life of the process. Meanwhile the disk is healthy, the on-disk DB files are not corrupt (quick_check/integrity_check = ok), ctx_doctor reports all-green, and a different context-mode server process on the same machine works fine. The only recovery is restarting that MCP server.
This looks like the same root cause as #880 (ContentStore singleton poisoned to a permanent disk I/O error by a cleanupStaleContentDBs race across parallel MCP servers) and #905 (Bun bun:sqlite SQLITE_IOERR), observed here from Claude Code rather than the Pi bridge. Filing with a clean OS-level reproduction + a ctx_doctor gap; please dedupe into #880/#905 if appropriate.
Environment
- context-mode 1.0.169 (Claude Code plugin form)
- Runtime: Bun 1.3.10 (
/opt/homebrew/bin/bun … /1.0.169/start.mjs) - macOS 26.5.2 (build 25F84), arm64
- 4 concurrent
context-mode … start.mjsprocesses running (multiple open Claude Code sessions across projects)
Symptom
In one session, every live store operation fails identically:
ctx_search → disk I/O error (SQLITE_IOERR)
ctx_index (tiny payload) → disk I/O error
ctx_fetch_and_index → disk I/O errorBoth reads and writes fail — so it is not a write-path/busy_timeout issue (cf. closed #667/#668) and not content-specific.
What was ruled out (evidence)
| Check | Result |
|---|---|
| Disk space / inodes | ✅ 125 GiB free, inodes 1%, storage dir writable |
ctx_doctor |
✅ green — FTS5/SQLite PASS, server test PASS |
PRAGMA quick_check / integrity_check on every content + session DB |
✅ ok |
Fresh sqlite3 CLI wal_checkpoint(TRUNCATE) on the active DB |
✅ `0 |
Live ctx_* ops in the affected server |
❌ every read & write → SQLITE_IOERR |
Same ctx_index from a different session's server, same machine |
✅ succeeds |
Tell-tale sign of a wedged live handle: the active content DB's WAL grew during observation (43c36a….db-wal 580 KB → 1.55 MB) and never checkpointed, while a fresh CLI handle to the same file checkpoints clean and passes quick_check. The data is intact; the connection is broken.
Likely mechanism
The live ContentStore (and/or SessionDB) bun:sqlite connection is poisoned into a persistent SQLITE_IOERR and never reopened. server.ts runs cleanupStaleContentDBs(contentDir, 14) on startup (≈ server.ts:728–729); with several servers alive, one server's startup sweep / another's handle can interact exactly as #880 describes, but here under Claude Code + Bun.
Two gaps make this worse than it needs to be:
- No self-heal on
IOERR.isSQLiteCorruptionError()(db-base.ts) matchesSQLITE_CORRUPT/SQLITE_NOTADB/"malformed"/"not a database" — it does not matchSQLITE_IOERR, so the rename-and-recreate / reopen recovery path never triggers. A live handle throwingIOERRon a provably-healthy file should reopen the connection (and, if it recurs, surface an actionable error) rather than fail every op forever. ctx_doctorblind spot.ctx_doctorexercises a scratch/:memory:DB, so it reports green while the liveContentStore/SessionDBhandle is wedged — producing the confusing "context-mode says everything's fine, yet nothing works" state.ctx_doctorshould probe the actual live handle with a trivial read/write and report it separately.
Workaround
Restart the affected MCP server — /mcp reconnect context-mode, or quit/reopen the session. The healthy DB files reattach cleanly and the 1.5 MB WAL checkpoints on first open. No ctx_purge / rebuild needed — the store is not corrupt.
Secondary: the error message misleads agents
A bare disk I/O error reads like a hardware/disk fault. In practice it repeatedly led an agent to conclude "the sandbox/disk is broken" and route around context-mode entirely (curl → temp file → read raw bytes into context), defeating the point of the tool. When a live-handle IOERR hits a healthy file/disk, the surfaced message should say so and recommend restarting the server, e.g. "context-mode server connection wedged (disk and DB are healthy) — restart the MCP server (/mcp reconnect)."
Related
- #880 — cleanupStaleContentDBs race poisons ContentStore singleton → permanent disk I/O error (likely same root cause)
- #905 — Bun/
bun:sqlitesame-turnctx_index→ctx_searchSQLITE_IOERR - #985 — multi-session contention on shared per-project content DB
- #667 / #668 (closed) — earlier
ctx_fetch_and_index"disk I/O error" (write-path/busy_timeout, node:sqlite) — distinct: this one fails reads too and is Bun
Source: mksglu/context-mode