{"record":{"id":"4d80872b165d926a","repo":"gitbutlerapp/gitbutler","slug":"download-failed-with-http-status-response-code","errorCode":null,"errorMessage":"Download failed with HTTP status: {response_code}","messagePattern":"Download failed with HTTP status: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/download.rs","lineNumber":129,"sourceCode":"            return Err(io_err).context(\"Failed to write downloaded data\");\n        }\n\n        // If perform failed for other reasons, propagate that error\n        perform_result.with_context(|| format!(\"Failed to download from {url}\"))?;\n    }\n\n    // Clear progress line\n    crate::ui::println_empty();\n\n    let response_code = easy\n        .response_code()\n        .context(\"Failed to get response code\")?;\n    if response_code == 403 {\n        bail!(\n            \"Download failed, the download artifact could not be found. Most likely, the but CLI has not been published for the requested version.\"\n        )\n    } else if response_code != 200 {\n        bail!(\"Download failed with HTTP status: {response_code}\");\n    }\n\n    // Validate the effective URL after following redirects\n    // This protects against malicious redirects to untrusted domains or insecure protocols\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    Ok(())\n}\n","sourceCodeStart":111,"sourceCodeEnd":144,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-installer/src/download.rs#L111-L144","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// HEAD-check the tarball URL before launching the installer\nlet resp = client.head(&tarball_url).send()?;\nif !resp.status().is_success() {\n    anyhow::bail!(\"artifact not ready: HTTP {}\", resp.status());\n}","typeGuard":null,"tryCatchPattern":"let mut attempt = 0u32;\nloop {\n    match run_install() {\n        Err(e) if e.to_string().contains(\"Download failed with HTTP status\") && attempt < 3 => {\n            attempt += 1;\n            std::thread::sleep(std::time::Duration::from_millis(500 * 2u64.pow(attempt)));\n        }\n        Err(e) if e.to_string().contains(\"artifact could not be found\") => {\n            break fall_back_to_latest_release(); // not retryable\n        }\n        other => break other,\n    }\n}","preventionTips":["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"],"tags":["rust","network","http","download","rate-limit","but-installer"],"backgroundTag":"http-download-failed","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}