{"record":{"id":"96faeecaa749751f","repo":"0x192/universal-android-debloater","slug":"unable-to-parse","errorCode":null,"errorMessage":"Unable to parse","messagePattern":"Unable to parse","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/core/uad_lists.rs","lineNumber":190,"sourceCode":"    }\n}\n\ntype PackageHashMap = HashMap<String, Package>;\npub fn load_debloat_lists(remote: bool) -> (Result<PackageHashMap, PackageHashMap>, bool) {\n    let cached_uad_lists: PathBuf = CACHE_DIR.join(\"uad_lists.json\");\n    let mut error = false;\n    let list: Vec<Package> = if remote {\n        retry(Fixed::from_millis(1000).take(60), || {\n            match ureq::get(\n                \"https://raw.githubusercontent.com/0x192/universal-android-debloater/\\\n           main/resources/assets/uad_lists.json\",\n            )\n            .call()\n            {\n                Ok(data) => {\n                    let text = data.into_string().expect(\"response should be Ok type\");\n                    fs::write(cached_uad_lists.clone(), &text).expect(\"Unable to write file\");\n                    let list = serde_json::from_str(&text).expect(\"Unable to parse\");\n                    OperationResult::Ok(list)\n                }\n                Err(e) => {\n                    warn!(\"Could not load remote debloat list: {}\", e);\n                    error = true;\n                    OperationResult::Retry(Vec::<Package>::new())\n                }\n            }\n        })\n        .map_or_else(|_| get_local_lists(), |list| list)\n    } else {\n        warn!(\"Could not load remote debloat list\");\n        get_local_lists()\n    };\n\n    // TODO: Do it without intermediary Vec?\n    let mut package_lists = HashMap::new();\n    for p in list {","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/0x192/universal-android-debloater/blob/11f27c671cba278d71296cdef4c5a5dba06add5e/src/core/uad_lists.rs#L172-L208","documentation":"The downloaded uad_lists.json text is parsed with serde_json::from_str(&text).expect(\"Unable to parse\"). The panic means the remote file was fetched but is not valid JSON or no longer matches the expected list schema (HashMap<String, Package>).","triggerScenarios":"A proxy/captive portal returns HTML instead of the JSON (which may still parse-fail after into_string succeeds), the upstream JSON is malformed, or the app's Package struct is out of sync with the repository's list format.","commonSituations":"Captive portal/ISP injection pages; GitHub serving an error page; app version older than a breaking change in the debloat list format; truncated download.","solutions":["Retry the download or verify network path returns the real raw.githubusercontent.com JSON","Update the app so the Package struct matches the current list schema","Match on from_str and fall back to get_local_lists() (bundled JSON) on parse failure","Inspect the downloaded file's first bytes to confirm it is JSON, not an HTML error page"],"exampleFix":"// before\nlet list = serde_json::from_str(&text).expect(\"Unable to parse\");\n// after\nlet list: Vec<Package> = match serde_json::from_str(&text) {\n    Ok(l) => l,\n    Err(e) => { warn!(\"Unable to parse remote list: {}\", e); return get_local_lists_retry(); }\n};","handlingStrategy":"fallback","validationCode":"let text = std::fs::read_to_string(\"uad_lists.json\")?;\nif !text.trim_start().starts_with('{') && !text.trim_start().starts_with('[') {\n    return Err(\"downloaded list is not JSON (proxy/portal page?)\".into());\n}","typeGuard":"fn looks_like_json(text: &str) -> bool {\n    let t = text.trim_start();\n    t.starts_with('{') || t.starts_with('[')\n}","tryCatchPattern":"let result = std::panic::catch_unwind(|| load_debloat_lists());\nif result.is_err() {\n    eprintln!(\"Unable to parse remote list — falling back to bundled list\");\n}","preventionTips":["Update the app when the upstream list schema changes","Detect captive-portal/HTML responses before parsing","Pin or verify the download URL returns the real raw JSON","Retain the bundled list as an always-available fallback"],"tags":["rust","serde","json","network","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"}