0x192/universal-android-debloater · error

Unable to write file

Error message

Unable to write file

What it means

After downloading the debloat list, the code writes the text to the cached file (CACHE_DIR/uad_lists.json) with fs::write(...).expect("Unable to write file"). A filesystem failure (missing cache directory, permissions, full disk) panics the application even though the download itself succeeded.

Source

Thrown at src/core/uad_lists.rs:189

        )
    }
}

type PackageHashMap = HashMap<String, Package>;
pub fn load_debloat_lists(remote: bool) -> (Result<PackageHashMap, PackageHashMap>, bool) {
    let cached_uad_lists: PathBuf = CACHE_DIR.join("uad_lists.json");
    let mut error = false;
    let list: Vec<Package> = if remote {
        retry(Fixed::from_millis(1000).take(60), || {
            match ureq::get(
                "https://raw.githubusercontent.com/0x192/universal-android-debloater/\
           main/resources/assets/uad_lists.json",
            )
            .call()
            {
                Ok(data) => {
                    let text = data.into_string().expect("response should be Ok type");
                    fs::write(cached_uad_lists.clone(), &text).expect("Unable to write file");
                    let list = serde_json::from_str(&text).expect("Unable to parse");
                    OperationResult::Ok(list)
                }
                Err(e) => {
                    warn!("Could not load remote debloat list: {}", e);
                    error = true;
                    OperationResult::Retry(Vec::<Package>::new())
                }
            }
        })
        .map_or_else(|_| get_local_lists(), |list| list)
    } else {
        warn!("Could not load remote debloat list");
        get_local_lists()
    };

    // TODO: Do it without intermediary Vec?
    let mut package_lists = HashMap::new();

View on GitHub (pinned to 11f27c671c)

Solutions

  1. Ensure the cache directory exists (create_dir_all on CACHE_DIR) before writing
  2. Check permissions and free disk space on the cache location
  3. Match on fs::write result and fall back to the bundled/embedded list instead of panicking
  4. Log and degrade gracefully: keep the in-memory list (it parses fine) even if caching fails

Example fix

// before
fs::write(cached_uad_lists.clone(), &text).expect("Unable to write file");
// after
let _ = fs::create_dir_all(cached_uad_lists.parent().unwrap());
if let Err(e) = fs::write(cached_uad_lists.clone(), &text) {
    warn!("Unable to write cache file: {}", e);
}
Defensive patterns

Strategy: validation

Validate before calling

let cache = dirs::cache_dir().unwrap().join("uad");
std::fs::create_dir_all(&cache)?;
let test = cache.join(".write_test");
std::fs::write(&test, b"ok")?;
std::fs::remove_file(&test)?; // cache dir is writable

Type guard

fn cache_writable(dir: &std::path::Path) -> bool {
    dir.exists() && std::fs::metadata(dir)
        .map(|m| !m.permissions().readonly())
        .unwrap_or(false)
}

Try / catch

let result = std::panic::catch_unwind(|| load_debloat_lists());
if result.is_err() {
    eprintln!("Unable to write file — check cache dir permissions/disk space");
}

Prevention

When it happens

Trigger: CACHE_DIR/uad (cache directory) does not exist or is unwritable when load_debloat_lists runs; disk full; antivirus/OS locking the file on Windows.

Common situations: First run where setup_uad_dir failed or was skipped; user cache dir redirected to a read-only location; low disk space; AppArmor/sandbox blocking the cache path.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of 0x192/universal-android-debloater@11f27c671c (2026-09-02). Data as JSON: /api/errors/535341e97b3ee893. Report an issue: GitHub.