{"record":{"id":"c91236fc0e5751b3","repo":"clockworklabs/SpacetimeDB","slug":"database-is-not-open","errorCode":null,"errorMessage":"database is not open","messagePattern":"database is not open","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/dst/src/engine.rs","lineNumber":138,"sourceCode":"    }\n\n    fn reopen_from_commitlog(&mut self) -> anyhow::Result<()> {\n        let db = self\n            .db\n            .take()\n            .ok_or_else(|| anyhow::anyhow!(\"replay without open database\"))?;\n\n        drop(db);\n\n        self.db = Some(Self::open_db(&self.commitlog, self.runtime_handle.clone())?);\n        Ok(())\n    }\n\n    fn count_state(&self) -> anyhow::Result<CountState> {\n        let db = self\n            .db\n            .as_ref()\n            .ok_or_else(|| anyhow::anyhow!(\"database is not open\"))?;\n        let tx = db.begin_tx(Workload::Internal);\n        let mut row_counts = Vec::with_capacity(self.table_ids.len());\n\n        for (table, table_id) in self.table_ids.iter().enumerate() {\n            let count = match db.iter(&tx, *table_id) {\n                Ok(iter) => iter.count() as u64,\n                Err(err) => {\n                    let _ = db.release_tx(tx);\n                    return Err(err.into());\n                }\n            };\n            row_counts.push(TableRowCount { table, count });\n        }\n\n        let _ = db.release_tx(tx);\n        Ok(CountState { row_counts })\n    }\n","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/dst/src/engine.rs#L120-L156","documentation":"In the dst (differential system testing) engine target, count_state() dereferences self.db, which is None whenever no database is open. init() always opens one, so in practice this fires after reopen_from_commitlog took the database and the re-open failed — i.e. an earlier Replay interaction failed and left the target without a db, and the next Replay (which calls count_state) or count_state itself hits the None.","triggerScenarios":"Issuing another Replay interaction after a prior Replay already failed inside open_db (commitlog replay error); calling count_state on a target whose init never completed; a driver that ignores an earlier error observation and keeps driving the target.","commonSituations":"DST/fuzz runs where the workload continues after a failed interaction; test drivers that do not stop on first error.","solutions":["Abort the test run on the first interaction error — target state is no longer valid","Rebuild the target via EngineTarget::init instead of continuing","Diagnose the underlying open/replay failure from the first error, not this message"],"exampleFix":"// before: keep driving the target after Replay failed\nengine.execute(&Interaction::Replay)?;\n\n// after: treat any interaction error as fatal for this run\nif let Err(e) = engine.execute(&Interaction::Replay) {\n    tracing::error!(%e, \"target broken; ending run\");\n    return;\n}","handlingStrategy":"validation","validationCode":"fn target_is_usable(target: &EngineTarget, last_ok: bool) -> bool {\n    last_ok // db is Some after successful init/reopen; a failed Replay leaves it None\n}","typeGuard":null,"tryCatchPattern":"In the driver, match on the execute() Result: on any Err, terminate the run for this target (its db may be gone) rather than issuing further interactions.","preventionTips":["Stop DST runs at the first interaction error","Rebuild the target via EngineTarget::init when a fresh run must continue","Log the first (root) error, not the cascade of database-is-not-open errors"],"tags":["rust","spacetimedb","dst","testing","engine"],"backgroundTag":"database-not-open","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}