{"record":{"id":"7804bd90938d260a","repo":"zeroclaw-labs/zeroclaw","slug":"sqlite-open-thread-exited-unexpectedly","errorCode":null,"errorMessage":"SQLite open thread exited unexpectedly","messagePattern":"SQLite open thread exited unexpectedly","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-memory/src/sqlite.rs","lineNumber":156,"sourceCode":"        open_timeout_secs: Option<u64>,\n    ) -> anyhow::Result<Connection> {\n        let path_buf = db_path.to_path_buf();\n\n        let conn = if let Some(secs) = open_timeout_secs {\n            let capped = secs.min(SQLITE_OPEN_TIMEOUT_CAP_SECS);\n            let (tx, rx) = mpsc::channel();\n            thread::spawn(move || {\n                let result = Connection::open(&path_buf);\n                let _ = tx.send(result);\n            });\n            match rx.recv_timeout(Duration::from_secs(capped)) {\n                Ok(Ok(c)) => c,\n                Ok(Err(e)) => return Err(e).context(\"SQLite failed to open database\"),\n                Err(mpsc::RecvTimeoutError::Timeout) => {\n                    anyhow::bail!(\"SQLite connection open timed out after {} seconds\", capped);\n                }\n                Err(mpsc::RecvTimeoutError::Disconnected) => {\n                    anyhow::bail!(\"SQLite open thread exited unexpectedly\");\n                }\n            }\n        } else {\n            Connection::open(&path_buf).context(\"SQLite failed to open database\")?\n        };\n\n        Ok(conn)\n    }\n\n    /// Initialize all tables: memories, FTS5, `embedding_cache`\n    fn init_schema(conn: &Connection) -> anyhow::Result<()> {\n        fn is_db_locked_error(e: &rusqlite::Error) -> bool {\n            use rusqlite::ffi::ErrorCode;\n            matches!(\n                e,\n                rusqlite::Error::SqliteFailure(err, _)\n                    if matches!(err.code, ErrorCode::DatabaseBusy | ErrorCode::DatabaseLocked)\n            )","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-memory/src/sqlite.rs#L138-L174","documentation":"open_connection()'s helper thread always sends its Connection::open result over a channel (even errors); RecvTimeoutError::Disconnected means the channel closed without a send — practically the thread panicked or died. Near-unreachable in practice; treat it as an environment or bug signal, not a config error.","triggerScenarios":"A panic inside Connection::open on the helper thread (allocator/OOM failure, stack exhaustion in SQLite FFI), thread-limit exhaustion, or a rusqlite/zeroclaw defect in the open path.","commonSituations":"Containers at memory or pids limits; hosts under heavy memory pressure; rare rusqlite ABI issues after a partial upgrade.","solutions":["Retry process startup once — transient OOM/thread pressure clears","Check thread and memory limits (ulimit -u, container pids/memory) and raise them if tight","Run with a panic hook/backtrace and inspect logs immediately before the error","If reproducible, update rusqlite/zeroclaw and file an issue with the backtrace"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before startup, confirm headroom so the open thread can't die\n// shell: ulimit -u (threads) and container memory limit comfortably above current usage","typeGuard":"fn is_sqlite_open_thread_died(e: &anyhow::Error) -> bool {\n    e.to_string().starts_with(\"SQLite open thread exited unexpectedly\")\n}","tryCatchPattern":"if let Err(e) = SqliteMemory::new(ws, timeout).await {\n    if is_sqlite_open_thread_died(&e) { return Err(e.context(\"restart the process; if it repeats, capture a panic backtrace\")); }\n    return Err(e);\n}","preventionTips":["Set generous container pids/memory limits","Install a panic hook that logs before abort","Retry startup once; persistent failures mean an environment or crate bug — report with the backtrace"],"tags":["sqlite","thread-panic","channel","runtime","rust"],"backgroundTag":"worker-thread-panic","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}