{"record":{"id":"e2d67836e062eca2","repo":"gitbutlerapp/gitbutler","slug":"download-of-url-failed-with-http-status-respon","errorCode":null,"errorMessage":"Download of {url} failed with HTTP status: {response_code}","messagePattern":"Download of (.+?) failed with HTTP status: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/download.rs","lineNumber":37,"sourceCode":"    {\n        let mut transfer = easy.transfer();\n        transfer\n            .write_function(|data| {\n                buf.borrow_mut().extend_from_slice(data);\n                Ok(data.len())\n            })\n            .context(\"Failed to set write function\")?;\n\n        transfer\n            .perform()\n            .with_context(|| format!(\"Failed to download from {url}\"))?;\n    }\n\n    let response_code = easy\n        .response_code()\n        .context(\"Failed to get response code\")?;\n    if response_code != 200 {\n        bail!(\"Download of {url} failed with HTTP status: {response_code}\");\n    }\n\n    let effective_url = easy\n        .effective_url()\n        .context(\"Failed to get effective URL\")?\n        .ok_or_else(|| anyhow!(\"Effective URL is missing\"))?;\n\n    crate::release::validate_download_url(effective_url)\n        .with_context(|| format!(\"Download was redirected to an untrusted URL: {effective_url}\"))?;\n\n    String::from_utf8(buf.into_inner()).context(\"Signature file is not valid UTF-8\")\n}\n\npub(crate) fn download_file(url: &str, dest: &Path) -> Result<()> {\n    let mut easy = create_client()?;\n\n    easy.url(url)\n        .with_context(|| format!(\"Failed to set URL: {url}\"))?;","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-installer/src/download.rs#L19-L55","documentation":"download_to_string() (Linux-only path, crates/but-installer/src/download.rs:11) fetches the minisign signature file for a release with libcurl and bails when the final HTTP status is anything other than 200. The message includes the failing URL and status code. This is the signature fetch that must succeed before verify_signature() can run, so the install aborts without touching the existing installation.","triggerScenarios":"The signature URL derived from the release metadata (platforms[\"linux-*\"].url plus .minisig) returns 404, 5xx, or a proxy-injected 407/502 during download_to_string(); e.g. releases.gitbutler.com incident, signature object never uploaded for that version, or a nightly whose artifacts were pruned between metadata fetch and signature download.","commonSituations":"CDN incidents; corporate proxies intercepting *.gitbutler.com; pinned old versions whose signature artifacts are missing; nightly channel races during publishing.","solutions":["Retry the install - transient 5xx/CDN errors are the most common cause","Try a different channel/version (plain 'but-installer' for latest release) if the pinned version's signature is permanently absent","curl -I the URL shown in the error message to confirm the status and whether a proxy alters it","Check GitButler status/GitHub releases to confirm the artifact exists"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Optional pre-flight: HEAD the signature URL before starting the install\nfn artifact_reachable(url: &str) -> anyhow::Result<bool> {\n    let mut easy = curl::easy::Easy::new();\n    easy.url(url)?;\n    easy.nobody(true)?; // HEAD request\n    easy.perform()?;\n    Ok(easy.response_code()? == 200)\n}","typeGuard":null,"tryCatchPattern":"let mut attempt = 0u32;\nloop {\n    match but_installer::run_installation_with_version(request.clone(), false) {\n        Ok(()) => break,\n        Err(e) if e.to_string().contains(\"failed with HTTP status\") && attempt < 2 => {\n            attempt += 1;\n            std::thread::sleep(std::time::Duration::from_secs(2 * attempt as u64));\n        }\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["Retry HTTP status failures with backoff - CDN hiccups are routine","Pre-flight check artifact URLs before starting an install job","Ensure egress to *.gitbutler.com is allowed; proxies often break signature fetches"],"tags":["rust","network","http","download","signature","linux","but-installer"],"backgroundTag":"http-download-failed","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}