0x192/universal-android-debloater · error

response should be Ok type

Error message

response should be Ok type

What it means

load_debloat_lists fetches uad_lists.json over HTTP with the `ureq` crate and calls data.into_string().expect("response should be Ok type"). into_string() returns Err when the HTTP response body cannot be read as UTF-8 text or the response was not successful (ureq responses with error status are Err-like). The expect turns that into a panic.

Source

Thrown at src/core/uad_lists.rs:188

            }
        )
    }
}

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?

View on GitHub (pinned to 11f27c671c)

Solutions

  1. Check network/proxy connectivity to raw.githubusercontent.com and retry the download
  2. Fall back to the cached uad_lists.json (already implemented via get_local_lists when the remote fails)
  3. Match on into_string() result instead of expect() and treat failure as the existing Retry path
  4. Add a timeout/retry with backoff around the HTTP call

Example fix

// before
let text = data.into_string().expect("response should be Ok type");
// after
let text = match data.into_string() {
    Ok(t) => t,
    Err(e) => { warn!("Could not read remote debloat list: {}", e); return OperationResult::Retry(Vec::new()); }
};
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check reachability before triggering the remote load
let resp = ureq::get("https://raw.githubusercontent.com/0x192/universal-android-debloater/main/resources/assets/uad_lists.json")
    .timeout(std::time::Duration::from_secs(10))
    .call();
let reachable = resp.as_ref().map(|r| r.status() == 200).unwrap_or(false);
if !reachable { eprintln!("remote list unreachable; will use cached list"); }

Type guard

fn is_ok_text_response(resp: &ureq::Response) -> bool {
    resp.status() == 200
        && resp.content_type().starts_with("text/")
}

Try / catch

let result = std::panic::catch_unwind(|| load_debloat_lists());
if result.is_err() {
    eprintln!("response should be Ok type — network issue; retry or use cached list");
}

Prevention

When it happens

Trigger: The GitHub raw request returns a non-2xx/failed response (proxy, rate limit, redirect failure) or a non-UTF-8 body, so into_string() errors while the outer .call() already returned Ok.

Common situations: Corporate proxies or captive portals returning HTML error pages; GitHub rate limiting (HTTP 429); TLS/DNS issues behind a partially-failed connection; a mirror returning binary content.

Related errors


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