{"record":{"id":"f1516fde257c2b92","repo":"gitbutlerapp/gitbutler","slug":"downloaded-file-is-empty","errorCode":null,"errorMessage":"Downloaded file is empty","messagePattern":"Downloaded file is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/install_macos.rs","lineNumber":360,"sourceCode":"    }\n\n    let required_binaries = [\"gitbutler-git-askpass\", \"gitbutler-tauri\"];\n\n    for binary in &required_binaries {\n        let binary_path = binaries_dir.join(binary);\n        if !binary_path.exists() {\n            bail!(\"Missing required binary: {binary}\");\n        }\n    }\n\n    Ok(())\n}\n\nfn validate_tarball(path: &Path) -> Result<()> {\n    // Check if file is not empty\n    let metadata = fs::metadata(path).context(\"Failed to read tarball metadata\")?;\n    if metadata.len() == 0 {\n        bail!(\"Downloaded file is empty\");\n    }\n\n    // Check for gzip magic bytes (1f 8b)\n    if !is_gzip_file(path)? {\n        bail!(\"Downloaded file does not appear to be a valid gzip archive\");\n    }\n\n    Ok(())\n}\n\n/// Check if a file has valid gzip magic bytes\nfn is_gzip_file(path: &Path) -> Result<bool> {\n    let mut file = File::open(path).context(\"Failed to open file\")?;\n    let mut magic_bytes = [0u8; 2];\n\n    // If we can't read 2 bytes, it's definitely not a valid gzip file\n    match file.read_exact(&mut magic_bytes) {\n        Ok(_) => Ok(magic_bytes == [0x1f, 0x8b]),","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-installer/src/install_macos.rs#L342-L378","documentation":"validate_tarball checks that the macOS app tarball downloaded by the installer is non-empty before attempting gzip validation. This error means fs::metadata reported a 0-byte file at the download destination, so the install is aborted rather than proceeding with a corrupt archive.","triggerScenarios":"download_and_install_app completed the HTTP download but wrote zero bytes to disk (failed transfer, empty response body, or the file was truncated/overwritten before validation).","commonSituations":"CDN/proxy returning an empty 200 response, network interruption mid-download, disk-full or permissions causing a truncated write, or a release asset published empty.","solutions":["Delete the partial file and retry the download","Check disk space and write permissions on the destination directory","Verify the release asset on the server is non-empty; re-publish if broken","Inspect network/proxy logs for aborted transfers"],"exampleFix":"// before\nlet resp = client.get(url).send()?;\nfs::write(path, resp.bytes()?);\n// after\nlet resp = client.get(url).send()?;\nlet bytes = resp.bytes()?;\nanyhow::ensure!(!bytes.is_empty(), \"empty response body for {url}\");\nfs::write(path, &bytes)?;","handlingStrategy":"validation","validationCode":"use std::fs;\nfn is_non_empty(path: &std::path::Path) -> bool {\n    fs::metadata(path).map(|m| m.len() > 0).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"Downloaded file is empty\") => {\n        // delete partial file and retry download\n    }\n    other => other?,\n}","preventionTips":["Verify HTTP response body length before writing to disk","Check Content-Length against bytes written","Retry failed/interrupted downloads with resumable ranges","Monitor disk space on the install target"],"tags":["download","file","install","macos"],"backgroundTag":"empty-response-body","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}