{"record":{"id":"cade49f1aa77bfbe","repo":"0x192/universal-android-debloater","slug":"unable-to-parse-backup-file","errorCode":null,"errorMessage":"Unable to parse backup file","messagePattern":"Unable to parse backup file","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/core/save.rs","lineNumber":88,"sourceCode":"    }\n}\n\npub fn list_available_backups(dir: &Path) -> Vec<DisplayablePath> {\n    #[allow(clippy::option_if_let_else)]\n    match fs::read_dir(dir) {\n        Ok(files) => files\n            .filter_map(|e| e.ok())\n            .map(|e| DisplayablePath { path: e.path() })\n            .collect::<Vec<_>>(),\n        Err(_) => vec![],\n    }\n}\n\npub fn list_available_backup_user(backup: DisplayablePath) -> Vec<User> {\n    match fs::read_to_string(backup.path) {\n        Ok(data) => {\n            let phone_backup: PhoneBackup =\n                serde_json::from_str(&data).expect(\"Unable to parse backup file\");\n\n            let mut users = vec![];\n            for u in phone_backup.users {\n                users.push(User {\n                    id: u.id,\n                    index: 0,\n                    protected: false,\n                });\n            }\n            users\n        }\n        Err(e) => {\n            error!(\"[BACKUP]: Selected backup file not found: {}\", e);\n            vec![]\n        }\n    }\n}\n","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/0x192/universal-android-debloater/blob/11f27c671cba278d71296cdef4c5a5dba06add5e/src/core/save.rs#L70-L106","documentation":"list_available_backup_user reads a backup JSON file and deserializes it into PhoneBackup with serde_json::from_str(...).expect(\"Unable to parse backup file\"). The panic means the file exists but is not valid JSON or does not match the PhoneBackup schema (users field shape/types).","triggerScenarios":"Selecting a backup file in update/list flow whose content is truncated, hand-edited, from an older app version with a different PhoneBackup schema, or not JSON at all.","commonSituations":"Restoring a backup produced by an older UAD version after struct fields were renamed; user edited or moved/corrupted the backup file; picking a non-backup file from the backup directory.","solutions":["Regenerate the backup with the current app version so the schema matches PhoneBackup","Validate the JSON (jq . backup.json) and fix syntax/field mismatches or restore from a good copy","Replace expect() with serde_json::from_str::<PhoneBackup>(&data) matched to skip or report invalid backups","Check the backup file was created by this app version and was not truncated during transfer"],"exampleFix":"// before\nlet phone_backup: PhoneBackup =\n    serde_json::from_str(&data).expect(\"Unable to parse backup file\");\n// after\nlet phone_backup: PhoneBackup = match serde_json::from_str(&data) {\n    Ok(b) => b,\n    Err(e) => { error!(\"Unable to parse backup file `{}`: {}\", backup.path().display(), e); return vec![]; }\n};","handlingStrategy":"validation","validationCode":"// Validate the backup before the library parses it\nlet data = std::fs::read_to_string(backup.path())?;\nlet v: serde_json::Value = serde_json::from_str(&data)?;\nif v.get(\"users\").and_then(|u| u.as_array()).is_none() {\n    return Err(\"backup file has no valid 'users' array\");\n}","typeGuard":"fn is_valid_backup(data: &str) -> bool {\n    serde_json::from_str::<serde_json::Value>(data)\n        .ok()\n        .map(|v| v.get(\"users\").map(|u| u.is_array()).unwrap_or(false))\n        .unwrap_or(false)\n}","tryCatchPattern":"match std::panic::catch_unwind(|| list_available_backup_user(backup.clone())) {\n    Ok(users) => users,\n    Err(_) => { eprintln!(\"Unable to parse backup file — regenerate it\"); vec![] }\n}","preventionTips":["Never hand-edit backup JSON; regenerate backups via the app","Check the backup was produced by the same app version","Keep multiple backups; verify one parses before deleting others","Copy files fully (verify size) before restoring"],"tags":["rust","serde","json","backup","panic"],"backgroundTag":"json-deserialization-failed","analyzedSha":"11f27c671cba278d71296cdef4c5a5dba06add5e","analyzedAt":"2026-09-02T16:12:43.433Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}