Hmbown/CodeWhale · error
failed to download skill
Error message
failed to download skill (last status: {}) What it means
`download_first_success` tried all candidate URLs; every one either was denied/prompted (returned earlier) or failed with an HTTP error status. After the loop, if no bytes were obtained and no network-policy outcome applies, it bails reporting the last HTTP status seen, or `unknown` if no request ever completed.
Solutions
- Check the reported last HTTP status and hit the URL manually to diagnose
- Verify the repo's default branch is `main` or `master`, or install via a direct tarball URL
- Retry later if the server returned a 5xx; check auth/proxy if 403
Example fix
// before
install("github:acme/skill", &skills_dir, MAX, &network, false).await?; // 404/404 -> bail
// after
let src = InstallSource::parse("https://git.example.com/acme/skill/archive/refs/heads/trunk.tar.gz")?;
install_with_registry(src, &skills_dir, MAX, &network, false, ®istry_url).await?; Defensive patterns
Strategy: retry
Try / catch
match download_first_success(&urls, &network, MAX).await {
Err(e) if e.to_string().contains("failed to download skill") => {
// inspect last status, retry transient 5xx with backoff
tokio::time::sleep(Duration::from_secs(2)).await;
retry_with_backoff(|| download_first_success(&urls, &network, MAX)).await?;
}
other => other?,
} Prevention
- Pre-check URLs with curl/HEAD before scripting installs
- Retry 5xx with exponential backoff
- Ensure public reachability of candidate URLs (no private repos without tokens)
When it happens
Trigger: All candidate URLs (e.g. GitHub main-branch and master-branch tarballs, or registry-listed URLs) returned non-success, non-404 statuses — 500s, 403 rate limits, etc. — or no URL was even attempted.
Common situations: GitHub repo with a non-`main`/`master` default branch (both tarball URLs 404... note 404s are tracked as NotFound and folded into this final bail); private repo returning 403/404-ish statuses; server outage returning 5xx; corporate proxy blocking requests.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- download failed with HTTP
- The update could not be downloaded. Your current app is…
- too many redirects starting at
- building bundle fetch client failed
- bundle fetch failed with HTTP status
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/d7c0e159ac7dacb4.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/skills/install.rs:1132
DownloadAttempt::Bytes(bytes) => {
return Ok(DownloadOutcome::Bytes {
bytes,
url: url.clone(),
});
}
DownloadAttempt::NotFound(status) => {
last_status = Some(status);
continue;
}
}
}
if let Some(host) = denied_host {
return Ok(DownloadOutcome::Denied(host));
}
if let Some(host) = prompt_host {
return Ok(DownloadOutcome::NeedsApproval(host));
}
bail!(
"failed to download skill (last status: {})",
last_status
.map(|s| s.to_string())
.unwrap_or_else(|| "unknown".to_string())
);
}
enum DownloadAttempt {
Bytes(Vec<u8>),
NotFound(reqwest::StatusCode),
}
/// Stream a URL into memory with a size cap. Aborts on the first read that
/// would push the buffer over `max_size * 4` (the *4 accounts for compression;
/// the unpack step still enforces `max_size` on the *uncompressed* bytes).
async fn download_with_cap(url: &str, max_size: u64) -> Result<DownloadAttempt> {
let resp = reqwest_client()
.get(url)View on GitHub (pinned to 73e0f67d83)