tonhowtf/omniget · error · anyhow::Error
unreachable: connect timed out after
Error message
unreachable: connect timed out after {:?} What it means
The HEAD request in probe_remote is wrapped in tokio::time::timeout. When the future does not complete within the configured timeout duration, the match falls into the Err(_) arm and the library returns this error, naming the elapsed duration. It indicates the host did not even establish/answer within the connect window.
Solutions
- Increase the timeout passed to probe_remote if the host is known to be slow.
- Confirm basic reachability with `curl -m <timeout> -I <url>` to reproduce outside the library.
- Check for firewall rules silently dropping packets (drop vs reject produces timeouts instead of refusals).
- Retry later — the target host may be temporarily overloaded or down.
Defensive patterns
Strategy: retry
Try / catch
match probe_remote(client, url, headers, timeout).await {
Err(e) if e.to_string().contains("connect timed out") => {
// retry once with a larger timeout before giving up
}
other => { other?; }
} Prevention
- Choose timeouts suited to the slowest expected link (mobile/satellite), not localhost latencies.
- Distinguish drop-style firewalls (timeouts) from reject-style (refusals) when debugging.
- Cache probe results briefly to avoid hammering a down host.
- Alert on hosts that repeatedly hit connect timeouts.
When it happens
Trigger: Calling probe/probe_url against a host that accepts no response within `timeout` — e.g. a firewalled host that silently drops SYN packets, or an overloaded server — so tokio::time::timeout fires on req.send().
Common situations: proof.ovh.net-style hosts that hang instead of refusing (the code comment cites a 495 s hang), over-aggressive timeout values on slow links, or packets dropped by middleboxes causing black-hole connects.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- unreachable
- probe timed out
- Download timeout — no data received for 30 seconds
- Timeout downloading segment
- read timed out after
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/ed419f624c27e3f6.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/http_fetcher.rs:684
}
let head = match tokio::time::timeout(timeout, req.send()).await {
Ok(Ok(r)) if r.status().is_success() => Some(r),
Ok(Ok(r)) => {
tracing::debug!("[http_fetcher] HEAD returned HTTP {}", r.status());
None
}
// Sem conexão não adianta tentar o GET de 1 byte: é o mesmo host.
// Falhar aqui poupa um segundo timeout inteiro por tentativa quando o
// servidor está fora (proof.ovh.net levou 495 s para desistir).
Ok(Err(e)) if e.is_connect() => {
return Err(anyhow!("unreachable: {}", e));
}
Ok(Err(e)) => {
tracing::debug!("[http_fetcher] HEAD failed: {}", e);
None
}
Err(_) => {
return Err(anyhow!(
"unreachable: connect timed out after {:?}",
timeout
));
}
};
if let Some(resp) = head {
let h = resp.headers();
let content_length = header_content_length(h);
let accept_ranges = h
.get(reqwest::header::ACCEPT_RANGES)
.and_then(|v| v.to_str().ok())
.map(|v| v.contains("bytes"))
.unwrap_or(false);
if content_length.is_some() {
return Ok(RemoteProbe {
content_length,
accept_ranges,View on GitHub (pinned to 8600b91f42)