"Session Not Found"? state.db Now Detects, Quarantines, and Heals Itself


You open Hermes to recover yesterday’s session and get a cold session not found — but you clearly remember it exists. Worse: state.db (the SQLite database where Hermes keeps all session history) gets corrupted entirely and months of conversations “vanish”. In the past this class of problem was nearly impossible to diagnose: the error message hid the real cause (database corruption), and the system kept writing into the broken database, making the damage snowball. A batch of fixes merged on August 30-31 (PR #99513 and its sibling PRs) gives Hermes, for the first time, a systematic way to handle database corruption: detect it, quarantine it, heal what can be healed, and tell you plainly when it can’t.

Why it was so hard to diagnose before

state.db is a SQLite file — robust in theory, but still corruptible after power loss, a full disk, a crashed process, or concurrent multi-process opens. In the past, Hermes’ attitude toward corruption was “pretend nothing happened”:

  • On reading bad data, the UI only showed session not found, swallowing the fact that “the database is corrupted”;
  • A structurally broken database kept accepting writes — new data poured into a broken store, like filling a leaking bucket;
  • A 0-byte empty file was mistaken for a “fresh database” and opened normally — until the first real write failed with attempt to write a readonly database;
  • With multiple processes opening the same database, one process could misclassify another process’s legitimately just-created empty database as corrupted and quarantine it.

What this batch fixes

Six PRs, spanning four phases: detection, quarantine, healing, and protection.

Detect corruption instead of pretending

  • Report “corruption” instead of “session not found” (PR #99529): corruption detection moves into the read path, so the problem surfaces with a clear message instead of a misleading error;
  • Structurally corrupt databases stop accepting writes (PR #99652): fail-closed — refuse writes rather than pour data into a broken store;
  • Read connections are bounded per file, not per SessionDB instance (PR #98691): previously each instance got its own connection budget, so connection counts ran away with multiple instances — a trigger for file-descriptor exhaustion and crashes.

Quarantine 0-byte files

  • A truncated 0-byte state.db is quarantined (PR #98017): the empty file is moved aside at startup instead of being opened as a normal database;
  • Cross-process lock fixes the quarantine race (PR #99513, sub-cluster A): the whole check → quarantine → connect → schema-commit sequence now runs under a cross-process lock, with a has_live_connection() guard protecting “empty but legitimately in use” databases — one process can no longer quarantine a sibling’s just-created database.

Self-heal the FTS full-text index

  • UnicodeDecodeError no longer breaks the index probe (PR #99513, sub-cluster B): corrupted full-text search (FTS) tables can throw decode errors, which previously killed read-only initialization and every read endpoint behind it; the probe and heal paths now catch these, and broken FTS tables are dropped and recreated.

Eliminate crash-class races

  • Unsynchronized reads on the shared writer connection are gone (PR #99502): this class could cause SIGSEGV-level crashes in extreme cases;
  • close()-vs-background-write races self-heal (PR #99509): when the write connection closes while writes are still in flight, the system repairs itself instead of silently dropping data.

What this means for you

If your session history has ever “mysteriously disappeared”, this batch changes the whole handling pipeline: detection up front → quarantine the bad file → heal what’s healable (FTS tables) → and when it can’t be healed, a clear error — while never continuing to write into the broken store. Session data reliability goes from “might vanish someday” to “at least the problem is explained and the damage stops growing”.

When you can use it

These PRs merged on August 30-31, 2026 and are all on main only — not yet in a release. Update to latest main to get the full protection; if you’ve hit session not found or lost sessions before, the error messages are now worth re-reading after upgrading — they tell you the database state directly.

Your session history is the working memory between you and Hermes — its reliability deserves care. For other ways to protect session data, see the session save & export guide and the 798-message amnesia postmortem; how compression interacts with history is covered in the one-call compaction guide.