Hmbown/CodeWhale · error
download {url} returned {status}
Error message
download {url} returned {status} What it means
Raised by download_with_cap for a single URL that answered with a non-success status other than 404. 404 is swallowed as NotFound so the candidate loop can try alternates; every other error status (403, 401, 5xx) bails here with the URL and status in the message. Because the bail propagates through '?' in the candidate loop, remaining candidate URLs are not tried after it, unlike the 404 path.
Source
Thrown at crates/tui/src/skills/install.rs:1156
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)
.send()
.await
.with_context(|| format!("failed to GET {url}"))?;
let status = resp.status();
if !status.is_success() {
if status == reqwest::StatusCode::NOT_FOUND {
return Ok(DownloadAttempt::NotFound(status));
}
bail!("download {url} returned {status}");
}
// Soft cap on the *compressed* download — well above max_size to allow
// for highly compressible payloads but still bounded.
let compressed_cap = max_size.saturating_mul(4);
let bytes = resp
.bytes()
.await
.with_context(|| format!("failed to read body of {url}"))?;
if (bytes.len() as u64) > compressed_cap {
bail!("download {url} exceeds compressed size cap of {compressed_cap} bytes");
}
Ok(DownloadAttempt::Bytes(bytes.to_vec()))
}
struct StagedSkill {
skill_name: String,
staged_path: PathBuf,
}View on GitHub (pinned to 0c42157ee5)
Solutions
- Act on the status: 401/403 means the artifact needs credentials or is private; 5xx means retry later.
- Fix or replace the URL; a moved artifact should get its new address.
- When using the github: shorthand and the first candidate errors (not 404), switch to a DirectUrl for the correct branch.
Example fix
# before /skill install https://cdn.example.com/pack.tar.gz # -> download ... returned 403 Forbidden # after: artifact requires auth; use the public mirror /skill install https://mirror.example.com/pack.tar.gz
Defensive patterns
Strategy: retry
Try / catch
for url in candidate_urls_after_failure {
match download_with_cap(&url, max_size).await {
Err(err) if err.to_string().contains("returned 403") || err.to_string().contains("returned 401") => {
continue; // auth-gated: try the next candidate URL, retrying will not help
}
Err(err) if err.to_string().contains("returned 5") => {
backoff_and_retry(&url).await; // transient server error
}
other => return other.map(|_| ()),
}
} Prevention
- Distinguish auth errors (401/403) from server errors (5xx): only the latter benefit from retry.
- Keep signed URLs fresh; expired ones return 401 immediately.
- Remember a non-404 error aborts the candidate loop, so supply fallback URLs yourself.
When it happens
Trigger: A direct-URL install pointing at a permission-gated artifact (403), an auth-required or expired signed URL (401), or a server error (500/502). With the github: shorthand, a non-404 error on the main-branch archive aborts before the master fallback is tried.
Common situations: Private or auth-required artifacts, rate-limited CDNs returning 403, expired signed URLs, and mirrors returning 502.
Related errors
- invalid download url: {url}
- failed to download skill (last status: {})
- download {url} exceeds compressed size cap of {compressed_ca
- FIM API error: HTTP {status}: {error_text}
- Anthropic API error (HTTP {status} {error_type}): {message}
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/f2511181f389f043.
Report an issue: GitHub.