0x192/universal-android-debloater · error
Unable to parse backup file
Error message
Unable to parse backup file
What it means
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).
Source
Thrown at src/core/save.rs:88
}
}
pub fn list_available_backups(dir: &Path) -> Vec<DisplayablePath> {
#[allow(clippy::option_if_let_else)]
match fs::read_dir(dir) {
Ok(files) => files
.filter_map(|e| e.ok())
.map(|e| DisplayablePath { path: e.path() })
.collect::<Vec<_>>(),
Err(_) => vec![],
}
}
pub fn list_available_backup_user(backup: DisplayablePath) -> Vec<User> {
match fs::read_to_string(backup.path) {
Ok(data) => {
let phone_backup: PhoneBackup =
serde_json::from_str(&data).expect("Unable to parse backup file");
let mut users = vec![];
for u in phone_backup.users {
users.push(User {
id: u.id,
index: 0,
protected: false,
});
}
users
}
Err(e) => {
error!("[BACKUP]: Selected backup file not found: {}", e);
vec![]
}
}
}
View on GitHub (pinned to 11f27c671c)
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
Example fix
// before
let phone_backup: PhoneBackup =
serde_json::from_str(&data).expect("Unable to parse backup file");
// after
let phone_backup: PhoneBackup = match serde_json::from_str(&data) {
Ok(b) => b,
Err(e) => { error!("Unable to parse backup file `{}`: {}", backup.path().display(), e); return vec![]; }
}; Defensive patterns
Strategy: validation
Validate before calling
// Validate the backup before the library parses it
let data = std::fs::read_to_string(backup.path())?;
let v: serde_json::Value = serde_json::from_str(&data)?;
if v.get("users").and_then(|u| u.as_array()).is_none() {
return Err("backup file has no valid 'users' array");
} Type guard
fn is_valid_backup(data: &str) -> bool {
serde_json::from_str::<serde_json::Value>(data)
.ok()
.map(|v| v.get("users").map(|u| u.is_array()).unwrap_or(false))
.unwrap_or(false)
} Try / catch
match std::panic::catch_unwind(|| list_available_backup_user(backup.clone())) {
Ok(users) => users,
Err(_) => { eprintln!("Unable to parse backup file — regenerate it"); vec![] }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unable to parse
- Could not write config file to disk!
- response should be Ok type
- Unable to write file
- Can't create cache directory
AI-assisted analysis of 0x192/universal-android-debloater@11f27c671c (2026-09-02).
Data as JSON: /api/errors/cade49f1aa77bfbe.
Report an issue: GitHub.