tonhowtf/omniget · error · anyhow::Error
Failed to download attachment
Error message
Failed to download attachment: {} What it means
download_attachment performs an HTTP GET for a course attachment via reqwest. If the request fails at the transport level (connection error, DNS failure, TLS error, timeout), the reqwest::Error is wrapped as "Failed to download attachment: {}". The download never got an HTTP response at all.
Solutions
- Check network connectivity to the attachment host (curl -v the URL to reproduce).
- Retry with backoff — transport errors are frequently transient.
- Verify proxy/VPN settings and that reqwest client config (timeouts, TLS features) matches the environment.
- Inspect the wrapped reqwest::Error message for the specific cause (DNS vs connect vs timeout) and fix that layer.
Example fix
// before
let resp = client.get(url).send().await
.map_err(|e| anyhow!("Failed to download attachment: {}", e))?;
// after
let resp = client.get(url).send().await
.map_err(|e| anyhow!("Failed to download attachment: {}", e))
.or_else(|e| async move {
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
client.get(url).send().await
.map_err(|e2| anyhow!("Failed to download attachment after retry: {}", e2))
})
.await?; Defensive patterns
Strategy: retry
Validate before calling
// Cheap reachability probe before the download
let host_ok = reqwest::Client::new().head(url).send().await.is_ok();
if !host_ok { eprintln!("Host unreachable; check network before retrying"); } Type guard
fn is_transport_error(e: &anyhow::Error) -> bool {
e.to_string().contains("Failed to download attachment")
} Try / catch
let mut attempt = 0;
loop {
match download_attachment(&client, &url, &dest, &token).await {
Err(e) if e.to_string().contains("Failed to download attachment") && attempt < 3 => {
attempt += 1;
tokio::time::sleep(Duration::from_secs(2u64.pow(attempt))).await;
}
other => break other,
}
} Prevention
- Configure reqwest client timeouts and connection pooling sensibly
- Retry transport errors with exponential backoff
- Check network/proxy/VPN state in deployment environments
- Log the inner reqwest::Error cause to distinguish DNS vs connect vs timeout
When it happens
Trigger: client.get(url).send().await returns Err — network unreachable, DNS resolution failure, TLS handshake failure, connection reset, or request timeout — while downloading a course attachment.
Common situations: Offline or flaky network; VPN/proxy interference; firewall blocking the course host; misconfigured DNS; server temporarily down; TLS certificate problems on the endpoint.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- download falhou: HTTP
- download de falhou: HTTP
- nao foi possivel buscar
- Failed to download aria2c: HTTP
- HTTP downloading
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/429f7d59426fa8cb.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/course_utils.rs:81
let path = format!("{}/{}", dir, filename);
if Path::new(&path).exists() {
let meta = std::fs::metadata(&path);
if meta.map(|m| m.len() > 0).unwrap_or(false) {
return Ok(0);
}
}
if cancel_token.is_cancelled() {
return Err(anyhow!("Download cancelled"));
}
let resp = client
.get(url)
.send()
.await
.map_err(|e| anyhow!("Failed to download attachment: {}", e))?;
if !resp.status().is_success() {
return Err(anyhow!(
"Attachment download failed: HTTP {}",
resp.status()
));
}
let bytes = resp.bytes().await?;
let size = bytes.len() as u64;
if size == 0 {
return Ok(0);
}
let part_path = format!("{}.part", path);
std::fs::write(&part_path, &bytes)?;
std::fs::rename(&part_path, &path)?;View on GitHub (pinned to 8600b91f42)