tonhowtf/omniget · error
HTTP {} downloading {}
Error message
HTTP {} downloading {} What it means
download_single_stream checks the HTTP status before reading the body: for both a fresh download (no existing bytes) and a resume where the server did not return 206 or 416, any non-success status (4xx/5xx other than the two handled cases) aborts the attempt with 'HTTP <status> downloading <url>'. It deliberately embeds the status code and URL so the caller can see exactly which request failed and why class of failure (auth, not-found, server error).
Solutions
- Read the embedded status code: 404 -> verify the URL/link still exists; 403/401 -> supply credentials via download_direct_with_headers headers (Authorization, Cookie, Referer); 429 -> back off and retry later; 5xx -> retry after the server recovers.
- Test the exact URL with curl -I to reproduce the status outside the app and inspect response headers (WWW-Authenticate, Retry-After) for the fix.
- Refresh expired signed/tokenized URLs before downloading.
- Add required headers (User-Agent, Referer) that hotlink-protected CDNs demand; a missing browser-like User-Agent commonly causes 403.
- If 5xx persists across retries, switch mirrors or inform the user the source is temporarily unavailable.
Example fix
// before
let file = downloader.download_direct("https://cdn.example.com/gone.mp4", &out).await?; // HTTP 403 downloading ...
// after
let mut headers = HeaderMap::new();
headers.insert(header::REFERER, "https://example.com/page".parse()?);
headers.insert(header::USER_AGENT, "Mozilla/5.0".parse()?);
headers.insert(header::COOKIE, format!("session={}", session_cookie).parse()?);
let file = downloader.download_direct_with_headers(&url, &out, &headers).await?; Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: classify the URL's status before committing to a download
async fn check_status(client: &reqwest::Client, url: &str) -> Result<u16, String> {
let r = client.head(url).send().await.map_err(|e| e.to_string())?;
Ok(r.status().as_u16())
} // 403/401 -> add headers; 404 -> refresh link; 429 -> wait; else proceed Try / catch
match downloader.download(&url, &out).await {
Err(e) if e.to_string().starts_with("HTTP ") => {
let msg = e.to_string(); // e.g. 'HTTP 403 downloading https://...'
let status: u16 = msg.split_whitespace().nth(1).and_then(|s| s.parse().ok()).unwrap_or(0);
match status {
401 | 403 => Err(anyhow!("auth/hotlink blocked; supply headers")),
404 => Err(anyhow!("file gone; refresh link")),
429 => Err(anyhow!("rate limited; back off")),
_ => Err(anyhow!("server error; retry later")),
}
}
other => other,
} Prevention
- Pre-flight HEAD the URL and branch on the status before downloading
- Send browser-like User-Agent plus Referer/Cookie/Authorization where the CDN expects them
- Refresh signed URLs before they expire to avoid 403s
- Honor Retry-After on 429/503 instead of hammering the retry loop
When it happens
Trigger: Any request during download/download_direct/download_direct_with_headers where the server replies with a non-2xx status — 404 for a removed file, 403 for forbidden/hotlink-protected content, 401 for missing auth, 429 rate-limiting, or 5xx server errors. For resumes, 200 instead of 206 also lands here (falls through to the non-success branch only if... it is success, so in practice 4xx/5xx).
Common situations: URL typo'd or file deleted (404); hotlink protection or missing Referer/Cookie/Authorization headers (403/401); aggressive rate limiting (429) especially across retry loops; temporary upstream outages (502/503); expired signed URLs returning 403.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- download de {} falhou: HTTP {}
- nao foi possivel buscar {}: {}
- Failed to download yt-dlp: HTTP {}
- HTTP {}
- download falhou: HTTP {}
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/2690f9297282fc86.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/direct_downloader.rs:504
if let Some(total) = total_size {
if existing_bytes >= total {
return Ok(());
}
}
request = request.header("Range", format!("bytes={}-", existing_bytes));
}
let response = request.send().await?;
let mut offset = 0u64;
if existing_bytes > 0 {
if response.status() == reqwest::StatusCode::PARTIAL_CONTENT {
offset = existing_bytes;
} else if response.status() == reqwest::StatusCode::RANGE_NOT_SATISFIABLE {
let _ = std::fs::remove_file(part_path);
return Err(anyhow!("Range not satisfiable, restarting"));
} else if !response.status().is_success() {
return Err(anyhow!("HTTP {} downloading {}", response.status(), url));
}
} else if !response.status().is_success() {
return Err(anyhow!("HTTP {} downloading {}", response.status(), url));
}
if let Some(ct) = response.headers().get("content-type") {
if let Ok(ct_str) = ct.to_str() {
if ct_str.contains("text/html") {
return Err(anyhow!(
"Server returned HTML instead of media — URL may have expired"
));
}
}
}
use std::io::Write;
let raw_file = if offset > 0 {
std::fs::OpenOptions::new().append(true).open(part_path)?View on GitHub (pinned to 8600b91f42)