{"record":{"id":"e53a4fa394aa40b4","repo":"diesel-rs/diesel","slug":"error-closing-sqlite-connection-error-message","errorCode":null,"errorMessage":"Error closing SQLite connection: {error_message}","messagePattern":"Error closing SQLite connection: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"diesel/src/sqlite/connection/raw.rs","lineNumber":916,"sourceCode":"        // Unregister before close so the boxed closures drop before sqlite3_close.\n        self.remove_update_hook();\n        self.remove_commit_hook();\n        self.remove_rollback_hook();\n        self.remove_progress_handler();\n        self.remove_wal_hook();\n        self.remove_busy_handler();\n        self.remove_authorizer();\n        self.remove_trace();\n        self.remove_collation_needed_hook();\n\n        let close_result = unsafe { ffi::sqlite3_close(self.internal_connection.as_ptr()) };\n        if close_result != ffi::SQLITE_OK {\n            let error_message = super::error_message(close_result);\n            if panicking() {\n                #[cfg(feature = \"std\")]\n                eprintln!(\"Error closing SQLite connection: {error_message}\");\n            } else {\n                panic!(\"Error closing SQLite connection: {error_message}\");\n            }\n        }\n    }\n}\n\nenum SqliteCallbackError {\n    Abort(&'static str),\n    DieselError(crate::result::Error),\n    Panic(String),\n}\n\nimpl SqliteCallbackError {\n    fn emit(&self, ctx: *mut ffi::sqlite3_context) {\n        let s;\n        let msg = match self {\n            SqliteCallbackError::Abort(msg) => *msg,\n            SqliteCallbackError::DieselError(e) => {\n                s = e.to_string();","sourceCodeStart":898,"sourceCodeEnd":934,"githubUrl":"https://github.com/diesel-rs/diesel/blob/6fa6ed01b24b24248ab2a611698d0a7c6a2e9120/diesel/src/sqlite/connection/raw.rs#L898-L934","documentation":"When a SqliteConnection is dropped, diesel calls sqlite3_close; if that returns a non-SQLITE_OK result the connection reports the failure. If the process is already panicking it only prints to stderr (std feature), otherwise it panics with \"Error closing SQLite connection: {message}\". It indicates the connection could not be cleanly finalized, usually because statements or prepared objects are still open.","triggerScenarios":"Dropping a SqliteConnection while sqlite3_close returns SQLITE_BUSY/SQLITE_LOCKED — e.g. unfinalized prepared statements, open blobs, or backup handles still referencing the connection; also happens during unwinding from a prior panic (stderr-only path).","commonSituations":"Holding a SqliteReadOnlyBlob, statement, or other derived handle beyond the connection's lifetime; leaking statements in long-lived processes; panics inside a transaction leaving dangling handles during unwind.","solutions":["Ensure all derived handles (blobs, statements, backup objects) are dropped before the connection itself goes out of scope — reorder bindings so the connection is declared last.","Explicitly finalize/drop prepared statements instead of leaking them (mem::forget, Box::leak, or static caches holding statements).","Check for other threads/processes holding the database open (SQLITE_BUSY) and close them or use busy_timeout.","If seen only during another panic's unwind, treat it as a secondary diagnostic and fix the root panic."],"exampleFix":"// before\nlet conn = SqliteConnection::establish(url)?;\nlet blob = SqliteReadOnlyBlob::new(&conn, ...)?;  // blob outlives usage scope ordering\n\n// after\nlet conn = SqliteConnection::establish(url)?;\n{ // blob scope ends before conn drops\n    let blob = SqliteReadOnlyBlob::new(&conn, ...)?;\n    // use blob\n}","handlingStrategy":"type-guard","validationCode":"// Struct-owning pattern: put the connection last in your struct / scope\ndrop(blob); drop(stmt); // ensure handles gone before conn drops","typeGuard":"fn conn_can_close(conn: &SqliteConnection) -> bool {\n    // no outstanding blobs/statements held elsewhere referencing conn\n    true // enforce by design: connection is dropped last in scope\n}","tryCatchPattern":"std::panic::catch_unwind(AssertUnwindSafe(|| drop(conn))) // during cleanup paths where panics must not propagate","preventionTips":["Declare the SqliteConnection before dependent handles so it drops last.","Never leak (mem::forget/Box::leak) statements derived from the connection.","Use busy_timeout and close other processes' handles before shutdown."],"tags":["sqlite","drop-panic","resource-cleanup","diesel"],"backgroundTag":"resource-cleanup-failed","analyzedSha":"6fa6ed01b24b24248ab2a611698d0a7c6a2e9120","analyzedAt":"2026-09-07T01:50:13.074Z","contentChangedAt":"2026-09-07T01:50:13.074Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}