gitbutlerapp/gitbutler · error

Downloaded file is empty

Error message

Downloaded file is empty

What it means

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.

Solutions

  1. Delete the partial file and retry the download
  2. Check disk space and write permissions on the destination directory
  3. Verify the release asset on the server is non-empty; re-publish if broken
  4. Inspect network/proxy logs for aborted transfers

Example fix

// before
let resp = client.get(url).send()?;
fs::write(path, resp.bytes()?);
// after
let resp = client.get(url).send()?;
let bytes = resp.bytes()?;
anyhow::ensure!(!bytes.is_empty(), "empty response body for {url}");
fs::write(path, &bytes)?;
Defensive patterns

Strategy: validation

Validate before calling

use std::fs;
fn is_non_empty(path: &std::path::Path) -> bool {
    fs::metadata(path).map(|m| m.len() > 0).unwrap_or(false)
}

Try / catch

match result {
    Err(e) if e.to_string().contains("Downloaded file is empty") => {
        // delete partial file and retry download
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/f1516fde257c2b92. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-installer/src/install_macos.rs:360

    }

    let required_binaries = ["gitbutler-git-askpass", "gitbutler-tauri"];

    for binary in &required_binaries {
        let binary_path = binaries_dir.join(binary);
        if !binary_path.exists() {
            bail!("Missing required binary: {binary}");
        }
    }

    Ok(())
}

fn validate_tarball(path: &Path) -> Result<()> {
    // Check if file is not empty
    let metadata = fs::metadata(path).context("Failed to read tarball metadata")?;
    if metadata.len() == 0 {
        bail!("Downloaded file is empty");
    }

    // Check for gzip magic bytes (1f 8b)
    if !is_gzip_file(path)? {
        bail!("Downloaded file does not appear to be a valid gzip archive");
    }

    Ok(())
}

/// Check if a file has valid gzip magic bytes
fn is_gzip_file(path: &Path) -> Result<bool> {
    let mut file = File::open(path).context("Failed to open file")?;
    let mut magic_bytes = [0u8; 2];

    // If we can't read 2 bytes, it's definitely not a valid gzip file
    match file.read_exact(&mut magic_bytes) {
        Ok(_) => Ok(magic_bytes == [0x1f, 0x8b]),

View on GitHub (pinned to 58e5313667)