herdrdev/herdr · error

download failed: {err}

Error message

download failed: {err}

What it means

This error wraps a failure to spawn the curl process used to download the remote herdr asset (curl_command().args([-sfL, --max-time 120, ...]).status()). The spawn error kind is preserved; curl itself failing produces the separate 'download failed' message without {err}.

Source

Thrown at src/remote/attach.rs:1441

    stdout
        .lines()
        .next()
        .map(str::trim)
        .is_some_and(|path| path.ends_with("/.local/bin/herdr"))
}

fn download_release_asset(platform: &RemotePlatform) -> io::Result<InstallSource> {
    let asset_key = platform.asset_key();
    let asset = remote_release_asset(&asset_key)?;

    let dir = private_download_dir(&asset_key)?;
    let path = dir.join("herdr.tmp");
    let status = crate::noninteractive_process::curl_command()
        .args(["-sfL", "--max-time", "120", "-o"])
        .arg(&path)
        .arg(&asset.url)
        .status()
        .map_err(|err| io::Error::new(err.kind(), format!("download failed: {err}")))?;
    if !status.success() {
        let _ = fs::remove_dir_all(&dir);
        return Err(io::Error::other("download failed"));
    }
    if let Some(expected) = &asset.sha256 {
        if let Err(err) = crate::checksum::verify_sha256(&path, expected) {
            let _ = fs::remove_dir_all(&dir);
            return Err(io::Error::new(
                err.kind(),
                format!("downloaded remote asset checksum verification failed: {err}"),
            ));
        }
    }

    Ok(InstallSource::temporary(path, dir))
}

fn fetch_remote_manifest(url: &str) -> io::Result<Vec<u8>> {

View on GitHub (pinned to f457cff4f2)

Solutions

  1. Verify curl is installed and on PATH: curl --version
  2. Install curl (apt/brew/apk) on the machine performing the download
  3. If PATH is stripped in non-interactive SSH, configure an absolute curl path or fix the environment
  4. Retry the attach after fixing curl

Example fix

# before: container without curl
# after
apt-get update && apt-get install -y curl
Defensive patterns

Strategy: fallback

Validate before calling

fn curl_available() -> bool {
    std::process::Command::new("curl")
        .arg("--version")
        .output()
        .map(|o| o.status.success())
        .unwrap_or(false)
}

Try / catch

match download_asset(url) {
    Err(e) if e.to_string().starts_with("download failed") && !curl_available() => {
        fetch_with_alternative_http_client(url)
    }
    r => r,
}

Prevention

When it happens

Trigger: curl is not installed on PATH, is not executable, or the process cannot be spawned (resource limits, exec format error) while downloading the remote release asset to a temp herdr.tmp file.

Common situations: Minimal containers or slim images without curl, PATH stripped in the SSH/non-interactive environment, or a corrupted curl binary.

Related errors


AI-assisted analysis of herdrdev/herdr@f457cff4f2 (2026-08-28). Data as JSON: /api/errors/4fd5fc0bd244becd. Report an issue: GitHub.