{"record":{"id":"5a93d452ef4a4ca6","repo":"t8y2/dbx","slug":"sqlite-backup-failed-error","errorCode":null,"errorMessage":"SQLite backup failed: {error}","messagePattern":"SQLite backup failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbx-sqlite-worker/src/runtime.rs","lineNumber":211,"sourceCode":"        }\n        Err(error) => WorkerBody::err(error.to_string()),\n    }\n}\n\nfn backup(conn: &Connection, dest: &str) -> WorkerBody {\n    if dest.trim().is_empty() || dest.contains('\\0') {\n        return WorkerBody::err(\"Backup destination is invalid\");\n    }\n    if let Some(parent) = Path::new(dest).parent() {\n        if !parent.as_os_str().is_empty() {\n            if let Err(error) = std::fs::create_dir_all(parent) {\n                return WorkerBody::err(error.to_string());\n            }\n        }\n    }\n    match conn.backup(DatabaseName::Main, dest, None) {\n        Ok(()) => WorkerBody::ok(),\n        Err(error) => WorkerBody::err(format!(\"SQLite backup failed: {error}\")),\n    }\n}\n\nfn restore(conn: &mut Connection, src: &str) -> WorkerBody {\n    if src.trim().is_empty() || src.contains('\\0') {\n        return WorkerBody::err(\"Restore source is invalid\");\n    }\n    match conn.restore(DatabaseName::Main, src, None::<fn(_)>) {\n        Ok(()) => WorkerBody::ok(),\n        Err(error) => WorkerBody::err(format!(\"SQLite restore failed: {error}\")),\n    }\n}\n\nfn value_to_json(value: rusqlite::types::ValueRef<'_>, column_decl_type: Option<&str>) -> (serde_json::Value, bool) {\n    match value {\n        rusqlite::types::ValueRef::Null => (json!(null), false),\n        rusqlite::types::ValueRef::Integer(value) => (json!(value), false),\n        rusqlite::types::ValueRef::Real(value) => (json!(value), false),","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/crates/dbx-sqlite-worker/src/runtime.rs#L193-L229","documentation":"conn.backup(DatabaseName::Main, dest, None) returned an error while performing an online SQLite backup; the worker wraps the rusqlite error in this message. Common underlying causes are I/O problems on the destination, a locked/busy source, or corruption.","triggerScenarios":"Destination file not writable or on a full filesystem; source database locked by another writer during the backup step; disk I/O error or SQLITE_BUSY/SQLITE_IOERR surfaced through the backup API.","commonSituations":"Backing up while the app holds long write transactions; backing up to a network mount that drops; permissions changed on the backup directory; disk quota exceeded.","solutions":["Read the wrapped {error} detail to identify the rusqlite/SQLite error code","Ensure the destination path is writable and the disk has space","Retry when the source database is not under heavy write load, or use a busy_timeout","Verify the destination directory exists and permissions allow file creation"],"exampleFix":"// before\nsend(Backup { dest: \"/mnt/net/b.db\" }); // IOERR\n// after\nlet dest = \"/var/backups/local/b.db\"; // local writable dir\nsend(Backup { dest }); // retry on busy with backoff","handlingStrategy":"retry","validationCode":"fn preflight_backup(conn: &rusqlite::Connection, dest: &str) -> Result<(), String> {\n    let parent = std::path::Path::new(dest).parent().ok_or(\"no parent dir\")?;\n    std::fs::create_dir_all(parent).map_err(|e| e.to_string())?;\n    let f = std::fs::OpenOptions::new().write(true).create(true).open(dest).map_err(|e| e.to_string())?;\n    drop(f);\n    Ok(())\n}","typeGuard":"fn backup_writable(dest: &str) -> bool {\n    std::path::Path::new(dest).parent().map_or(false, |p| std::fs::metadata(p).map_or(false, |m| !m.permissions().readonly()))\n}","tryCatchPattern":"match worker.send(WorkerOp::Backup { dest }).await {\n    Err(body) if body.error().map_or(false, |e| e.starts_with(\"SQLite backup failed:\")) => {\n        eprintln!(\"Backup failed: check disk space, permissions, and source locks; retrying\");\n        std::thread::sleep(Duration::from_secs(2));\n        worker.send(WorkerOp::Backup { dest }).await?\n    }\n    other => other?,\n}","preventionTips":["Preflight: ensure dest dir is writable and disk has space","Avoid backing up during long write transactions; set busy_timeout","Back up to local disk, then copy to network storage","Parse the wrapped rusqlite error code to branch (busy vs IO)"],"tags":["sqlite","backup","io","rusqlite"],"backgroundTag":"backup-failed","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}