tonhowtf/omniget · error · anyhow::Error
read timed out after {:?}
Error message
read timed out after {:?} What it means
Thrown in download_streaming when tokio::time::timeout(self.config.read_timeout, stream.next()) elapses — i.e. no new chunk arrived within the configured read_timeout duration. This is an inactivity timeout per chunk read, not a total download time limit; a download is only killed if the stream stalls completely for read_timeout. The .part file keeps data received so far.
Solutions
- Increase config.read_timeout to a value comfortably above the worst-case inter-chunk delay (e.g. 30-60s for slow mirrors).
- Retry the download with resume so the .part file is continued from where the stall occurred.
- Add an automatic retry wrapper around download for timeout errors with exponential backoff.
- Check whether the source server/CDN is throttling or stalling; try an alternate mirror or HTTP/1.1 instead of HTTP/2.
- Keep TCP keepalives enabled on the client (reqwest/hyper defaults) so dead connections error out quickly instead of silently stalling.
Example fix
// before
let config = FetcherConfig { read_timeout: Duration::from_secs(3), ..Default::default() };
// after
let config = FetcherConfig { read_timeout: Duration::from_secs(60), ..Default::default() }; Defensive patterns
Strategy: retry
Validate before calling
// don't start with an unreasonably small read_timeout
if config.read_timeout < Duration::from_secs(15) {
bail!("read_timeout {:?} too small for downloads", config.read_timeout);
} Try / catch
match fetcher.download(&mut tx).await {
Err(e) if e.to_string().contains("read timed out") => {
// stall: resume download with backoff, escalate timeout per attempt
for attempt in 0..3 {
tokio::time::sleep(Duration::from_secs(1 << attempt)).await;
if fetcher.download_resuming(&mut tx).await.is_ok() { break; }
}
}
other => other?,
} Prevention
- Set read_timeout generously (30-60s) for downloads from slow or throttled mirrors.
- Remember it's a per-chunk inactivity timeout, not a total-duration cap — size it for worst-case stalls.
- Always combine with resume support so a timeout doesn't discard prior progress.
- Watch for stalls right after system sleep/resume or network handoffs; reconnect proactively.
When it happens
Trigger: The remote server or an intermediary stops sending data for longer than self.config.read_timeout while the connection stays open: stalled transfer, server-side hang, dead NAT connection, or a read_timeout configured too aggressively for a slow/throttled source.
Common situations: read_timeout set to a few seconds while downloading from a slow/throttled mirror; server pauses to handle load; laptop resumed from sleep with a half-dead TCP connection; mobile network handoff stalling the stream; VPN tunnel momentarily freezing.
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
- Download timeout — no data received for 30 seconds
- stream error: {}
- connect timeout
- Connection timed out. Check your internet and try again.
- download falhou: HTTP {}
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/5f0f51e0f4f550f2.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/http_fetcher.rs:378
None,
),
};
let _ = progress_tx
.send(ProgressUpdate::rich(
pct,
Some(downloaded),
total.filter(|t| *t > 0),
speed,
eta,
))
.await;
last_emit = std::time::Instant::now();
}
}
Ok(Some(Err(e))) => return Err(anyhow!("stream error: {}", e)),
Ok(None) => break,
Err(_) => {
return Err(anyhow!(
"read timed out after {:?}",
self.config.read_timeout
))
}
}
}
file.flush().await?;
drop(file);
tokio::fs::rename(part_path, &self.output_path).await?;
let _ = progress_tx.send(ProgressUpdate::percent(100.0)).await;
Ok(HttpFetcherResult {
bytes_written: downloaded,
})
}
async fn download_chunked(
&self,View on GitHub (pinned to 8600b91f42)