{"record":{"id":"129450016593ab0d","repo":"t8y2/dbx","slug":"failed-to-open-storage-129450","errorCode":null,"errorMessage":"Failed to open storage","messagePattern":"Failed to open storage","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src-tauri/src/lib.rs","lineNumber":1510,"sourceCode":"            append_startup_probe(\"resolving app data dir\");\n            let default_data_dir =\n                app.path().app_data_dir().map_err(|e| e.to_string()).expect(\"Failed to resolve app data dir\");\n            let data_dir_resolution = data_dir::resolve_data_dir_with_mode(default_data_dir);\n            let data_dir = data_dir_resolution.data_dir.clone();\n            std::fs::create_dir_all(&data_dir).expect(\"Failed to create data dir\");\n            let data_dir_mode = startup_data_dir_mode(&data_dir_resolution.mode);\n            append_startup_probe(format!(\"data dir ready mode={data_dir_mode}\"));\n            let alternative_data_dir = data_dir::alternative_data_dir(&data_dir_resolution);\n            match maybe_import_user_data_db(&data_dir, alternative_data_dir.as_deref()) {\n                Ok(result) => eprintln!(\"[STARTUP] data db fallback import: {result:?}\"),\n                Err(err) => eprintln!(\"[STARTUP] data db fallback import failed: {err}\"),\n            }\n            let db_path = data_dir.join(\"dbx.db\");\n\n            let t = Instant::now();\n            append_startup_probe(format!(\"opening storage file=dbx.db data_dir_mode={data_dir_mode}\"));\n            let storage = tauri::async_runtime::block_on(async {\n                let s = Storage::open(&db_path).await.expect(\"Failed to open storage\");\n                eprintln!(\"[STARTUP]   Storage::open in {:?}\", t.elapsed());\n                append_startup_probe(format!(\"storage opened in {:?}\", t.elapsed()));\n                let t2 = Instant::now();\n                s.migrate_from_json(&data_dir).await.expect(\"Failed to migrate JSON data\");\n                eprintln!(\"[STARTUP]   migrate_from_json in {:?}\", t2.elapsed());\n                append_startup_probe(format!(\"json migration completed in {:?}\", t2.elapsed()));\n                s\n            });\n            let desktop_settings = tauri::async_runtime::block_on(storage.load_desktop_settings()).unwrap_or_default();\n            app.handle().plugin(\n                tauri_plugin_log::Builder::default()\n                    .timezone_strategy(tauri_plugin_log::TimezoneStrategy::UseLocal)\n                    .format(|out, message, record| {\n                        out.finish(format_args!(\n                            \"[{}][{}][{}] {}\",\n                            chrono::Local::now().format(\"%Y-%m-%d][%H:%M:%S%.3f\"),\n                            record.level(),\n                            record.target(),","sourceCodeStart":1492,"sourceCodeEnd":1528,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/src-tauri/src/lib.rs#L1492-L1528","documentation":"The app opens its SQLite-based Storage at <data_dir>/dbx.db with Storage::open(&db_path) and panics on failure. Opening fails when the file exists but is not a valid/corrupt database, the path is unwritable, or the database engine cannot initialize the file (locking, I/O errors).","triggerScenarios":"Storage::open(&db_path).await at lib.rs:1510 erroring because dbx.db is corrupted or encrypted garbage, the data dir lacks write permission, another process holds an exclusive lock, or disk I/O fails during initialization.","commonSituations":"Crash or power loss left a truncated dbx.db; antivirus/backup tools locking the file; data dir restored from a partial backup; disk full while WAL/journal files are created.","solutions":["Move the corrupt dbx.db (and -wal/-shm siblings) aside so a fresh database is created, after backing it up for recovery.","Check for lockers (antivirus, sync clients like Dropbox/OneDrive, second app instance) and exclude the data dir from them.","Verify write permissions and free space in the data dir; propagate the Storage::open error instead of expect() to enable fallback to the alternative data dir."],"exampleFix":"// before\nlet s = Storage::open(&db_path).await.expect(\"Failed to open storage\");\n// after\nlet s = match Storage::open(&db_path).await {\n    Ok(s) => s,\n    Err(e) => {\n        std::fs::rename(&db_path, db_path.with_extension(\"db.corrupt\")).ok();\n        Storage::open(&db_path).await.expect(\"Failed to open storage after reset\")\n    }\n};","handlingStrategy":"fallback","validationCode":"// Rust: probe the db file before opening\nfn db_looks_recoverable(path: &std::path::Path) -> bool {\n    match std::fs::read(path) {\n        Ok(bytes) => bytes.starts_with(b\"SQLite format 3\\u{0}\"),\n        Err(_) => true, // missing file is fine: fresh open\n    }\n}","typeGuard":null,"tryCatchPattern":"let storage = match Storage::open(&db_path).await {\n    Ok(s) => s,\n    Err(e) => {\n        eprintln!(\"Storage::open failed: {e}; moving corrupt db aside\");\n        std::fs::rename(&db_path, db_path.with_extension(\"db.corrupt\")).ok();\n        Storage::open(&db_path).await?\n    }\n};","preventionTips":["Back up dbx.db (with -wal/-shm) before app upgrades.","Exclude the data dir from antivirus/sync tools that lock or half-sync SQLite files.","Use SQLite integrity_check on startup and quarantine corrupt databases instead of panicking."],"tags":["rust","sqlite","database","storage","startup"],"backgroundTag":"database-open-failed","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}