{"record":{"id":"25bd048866555b51","repo":"Hmbown/CodeWhale","slug":"failed-to-enable-wal-for-sqlite-retained-journ","errorCode":null,"errorMessage":"failed to enable WAL for {}: SQLite retained journal mode {configured_mode}","messagePattern":"failed to enable WAL for (.+?): SQLite retained journal mode (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/state/src/lib.rs","lineNumber":345,"sourceCode":"        conn.busy_timeout(std::time::Duration::from_secs(5))\n            .with_context(|| format!(\"failed to set busy_timeout for {}\", db_path.display()))?;\n        conn.pragma_update(None, \"foreign_keys\", \"ON\")\n            .with_context(|| format!(\"failed to enable foreign keys for {}\", db_path.display()))?;\n\n        // WAL persists in the database header, so established stores need no\n        // write-like journal transition on every process start. Fresh or\n        // explicitly downgraded stores still transition once, and we verify\n        // SQLite accepted the requested mode instead of silently retaining the\n        // previous one (for example on an unsupported VFS).\n        let journal_mode: String = conn\n            .pragma_query_value(None, \"journal_mode\", |row| row.get(0))\n            .with_context(|| format!(\"failed to read journal mode for {}\", db_path.display()))?;\n        if !journal_mode.eq_ignore_ascii_case(\"wal\") {\n            let configured_mode: String = conn\n                .pragma_update_and_check(None, \"journal_mode\", \"WAL\", |row| row.get(0))\n                .with_context(|| format!(\"failed to enable WAL for {}\", db_path.display()))?;\n            if !configured_mode.eq_ignore_ascii_case(\"wal\") {\n                anyhow::bail!(\n                    \"failed to enable WAL for {}: SQLite retained journal mode {configured_mode}\",\n                    db_path.display()\n                );\n            }\n        }\n        Ok(())\n    }\n\n    /// Returns the filesystem path of the underlying SQLite database.\n    pub fn db_path(&self) -> &Path {\n        &self.db_path\n    }\n\n    fn conn(&self) -> Result<MutexGuard<'_, Connection>> {\n        // Poisoning means a panic mid-operation; any open transaction was\n        // rolled back when it dropped, but surface the condition rather than\n        // silently continuing on a connection whose state we can't vouch for.\n        self.conn","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/state/src/lib.rs#L327-L363","documentation":"The state store requires SQLite databases to run in WAL (write-ahead logging) journal mode for concurrent readers. configure_connection issues PRAGMA journal_mode=WAL and checks the mode SQLite actually switched to; some conditions make SQLite silently keep the old mode (e.g. 'delete'), and the code then bails rather than continue with degraded durability.","triggerScenarios":"Opening/initializing the database when SQLite refuses or fails to switch journal_mode to WAL — commonly because another connection holds the database in a different mode, the file is on a network filesystem that doesn't support WAL shared memory, or a transaction is active on the connection.","commonSituations":"Database on NFS/SMB/network mounts (classic WAL failure); another process/connection with an open transaction or lock; copying a non-WAL db file over the live one mid-run; very old SQLite builds; read-only filesystem (pragma_update itself would fail first).","solutions":["Move the database file to a local filesystem (WAL needs shared memory, unavailable on NFS/SMB).","Close other connections/processes holding the DB before opening, so the mode switch isn't blocked.","Run PRAGMA journal_mode; manually to see the retained mode and diagnose.","Ensure no explicit transaction is open on the connection when the pragma runs.","Check the SQLite version supports WAL (>= 3.7.0)."],"exampleFix":"// before: db on network share\nlet db = StateDb::open(\"/mnt/nfs/codewhale/state.db\")?; // fails WAL\n// after: local data dir\nlet db = StateDb::open(\"~/.local/state/codewhale/state.db\")?;","handlingStrategy":"fallback","validationCode":"// Detect unsuitable filesystems before opening the db\nlet meta = std::fs::metadata(db_path.parent().unwrap())?;\n// e.g. reject known network mount points or check /proc/mounts for nfs/cifs","typeGuard":"fn is_local_path(p: &Path) -> bool {\n    p.starts_with(\"/home\") || p.starts_with(\"/Users\") || p.starts_with(\"/tmp\")\n}","tryCatchPattern":"match StateDb::open(db_path) {\n    Ok(db) => db,\n    Err(e) if e.to_string().contains(\"retained journal mode\") => {\n        eprintln!(\"WAL unavailable on {db_path:?}; use a local disk\");\n        StateDb::open(local_fallback_path())?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Place SQLite databases on local filesystems, never NFS/SMB","Ensure no other process holds the db open with an active transaction","Check PRAGMA journal_mode after opening to detect drift early","Keep SQLite >= 3.7.0"],"tags":["sqlite","database","wal"],"backgroundTag":"invalid-config-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}