gitbutlerapp/gitbutler · error
Download failed with HTTP status: {response_code}
Error message
Download failed with HTTP status: {response_code} What it means
download_file() checks the final HTTP status after transferring the CLI tarball and bails for any code that is neither 200 nor 403. Unlike the dedicated 403 branch, this indicates a transport or server problem (404 stale URL, 429 rate limit, 5xx) rather than a missing artifact. Nothing is installed and the previous installation is untouched.
Source
Thrown at crates/but-installer/src/download.rs:129
return Err(io_err).context("Failed to write downloaded data");
}
// If perform failed for other reasons, propagate that error
perform_result.with_context(|| format!("Failed to download from {url}"))?;
}
// Clear progress line
crate::ui::println_empty();
let response_code = easy
.response_code()
.context("Failed to get response code")?;
if response_code == 403 {
bail!(
"Download failed, the download artifact could not be found. Most likely, the but CLI has not been published for the requested version."
)
} else if response_code != 200 {
bail!("Download failed with HTTP status: {response_code}");
}
// Validate the effective URL after following redirects
// This protects against malicious redirects to untrusted domains or insecure protocols
let effective_url = easy
.effective_url()
.context("Failed to get effective URL")?
.ok_or_else(|| anyhow!("Effective URL is missing"))?;
crate::release::validate_download_url(effective_url)
.with_context(|| format!("Download was redirected to an untrusted URL: {effective_url}"))?;
Ok(())
}
View on GitHub (pinned to caf1f223d3)
Solutions
- Retry with exponential backoff - 5xx and 429 are transient
- curl -v the URL to see the exact status; a 404 means metadata/CDN skew, retry later or use another version
- Reduce install frequency or cache artifacts in CI to avoid 429s
- Check GitButler status pages for an ongoing release incident
Defensive patterns
Strategy: retry
Validate before calling
// HEAD-check the tarball URL before launching the installer
let resp = client.head(&tarball_url).send()?;
if !resp.status().is_success() {
anyhow::bail!("artifact not ready: HTTP {}", resp.status());
} Try / catch
let mut attempt = 0u32;
loop {
match run_install() {
Err(e) if e.to_string().contains("Download failed with HTTP status") && attempt < 3 => {
attempt += 1;
std::thread::sleep(std::time::Duration::from_millis(500 * 2u64.pow(attempt)));
}
Err(e) if e.to_string().contains("artifact could not be found") => {
break fall_back_to_latest_release(); // not retryable
}
other => break other,
}
} Prevention
- Backoff-and-retry any generic HTTP status failure before surfacing it
- Cache or pin release artifacts in CI to reduce download calls (429 avoidance)
- Watch app.gitbutler.com/releases freshness when installing immediately after a release
When it happens
Trigger: 404 when the platform URL in the release metadata is stale or wrong; 5xx during a CDN incident; 429 from repeated automated installs; proxies or middleboxes returning 502/504 for releases.gitbutler.com.
Common situations: CI pipelines hammering the download host and hitting rate limits; CDN partial outages; metadata/CDN skew right after a release where the JSON updates before objects propagate.
Related errors
- Download of {url} failed with HTTP status: {response_code}
- Failed to get latest pipeline for ref: {status}
- Request failed: {e}
- push failed
- GitHub GraphQL request failed: {}
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/4d80872b165d926a.
Report an issue: GitHub.