tonhowtf/omniget · error
Connection to relay timed out (10s)
Error message
Connection to relay timed out (10s)
What it means
connect_relay dials the P2P relay address (relay_addr()) wrapped in a 10-second tokio::time::timeout around TcpStream::connect. When the timeout elapses before the TCP connection completes, the elapsed error is mapped to this message. It means the relay host was unreachable (or too slow) within 10 seconds; a failed connect that returns promptly is instead reported as 'Failed to connect to relay ...'.
Solutions
- Verify the relay is running and reachable: `nc -vz <host> <port>` against the address from relay_addr().
- Check relay_addr() configuration — wrong host/port is the most common cause of connect timeouts rather than refused connections.
- Test from the same network without firewall/VPN to rule out blocked egress on the relay port.
- Increase the 10s timeout if the relay is known to be slow, or add retry with backoff for transient network issues.
- Surface a user-facing 'relay unreachable' state and fall back to non-relay transfer if applicable.
Example fix
// before
let stream = tokio::time::timeout(
std::time::Duration::from_secs(10),
TcpStream::connect(&addr),
).await.map_err(|_| anyhow!("Connection to relay timed out (10s)"))?...
// after
const RELAY_TIMEOUT: Duration = Duration::from_secs(10);
let mut attempt = 0;
let stream = loop {
attempt += 1;
match tokio::time::timeout(RELAY_TIMEOUT, TcpStream::connect(&addr)).await {
Ok(res) => break res.map_err(|e| anyhow!("Failed to connect to relay {}: {}", addr, e))?,
Err(_) if attempt < 3 => tokio::time::sleep(Duration::from_secs(2 * attempt)).await,
Err(_) => return Err(anyhow!("Connection to relay {} timed out after {} attempts", addr, attempt)),
}
}; Defensive patterns
Strategy: retry
Validate before calling
// Rust: probe relay reachability before starting a relay-based transfer
async fn relay_reachable() -> bool {
let addr = relay_addr();
tokio::time::timeout(Duration::from_secs(3), TcpStream::connect(&addr))
.await
.map(|r| r.is_ok())
.unwrap_or(false)
} Try / catch
match p2p_download(opts).await {
Err(e) if e.to_string().contains("Connection to relay timed out") => {
// relay unreachable; retry with backoff or switch to direct/LAN transfer
tokio::time::sleep(Duration::from_secs(5)).await;
p2p_download(opts).await
}
other => other,
} Prevention
- Verify relay host/port configuration before starting transfers (nc -vz <host> <port>)
- Run a lightweight health check against the relay on app startup
- Allow more than 10s (or add retries with backoff) on slow or high-latency networks
- Check firewall/NAT rules for the relay port on both peers
- Provide a non-relay fallback path when the relay is unreachable
When it happens
Trigger: Calling download or run_sender (the two connect_relay callers) while the relay at relay_addr() is down, firewalled, DNS-resolving to a blackhole address, or the network path drops SYN packets so connect never completes within 10s.
Common situations: Relay server not running or restarted; wrong host/port in configuration (relay_addr()); corporate/NAT firewall blocking the relay port; IPv6 address attempted but unroutable, causing silent packet drop; relay under overload accepting connections slowly.
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
- Failed to connect to relay {}: {}
- Connection to relay timed out (10s)
- Relay closed connection unexpectedly
- Relay closed connection unexpectedly
- Failed to connect to relay {}: {}
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/f2e801c5f9ccd257.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/platforms/p2p.rs:29
use tokio_util::sync::CancellationToken;
use crate::models::media::{DownloadOptions, DownloadResult, MediaInfo, MediaType, VideoQuality};
use crate::platforms::traits::PlatformDownloader;
const CHUNK_SIZE: usize = 64 * 1024;
fn relay_addr() -> String {
std::env::var("OMNIGET_RELAY").unwrap_or_else(|_| "relay.tonho.wtf:9009".to_string())
}
async fn connect_relay() -> anyhow::Result<TcpStream> {
let addr = relay_addr();
let stream = tokio::time::timeout(
std::time::Duration::from_secs(10),
TcpStream::connect(&addr),
)
.await
.map_err(|_| anyhow!("Connection to relay timed out (10s)"))?
.map_err(|e| anyhow!("Failed to connect to relay {}: {}", addr, e))?;
Ok(stream)
}
async fn read_line(
reader: &mut BufReader<tokio::io::ReadHalf<TcpStream>>,
) -> anyhow::Result<String> {
let mut line = String::new();
let n = reader.read_line(&mut line).await?;
if n == 0 {
anyhow::bail!("Relay closed connection unexpectedly");
}
Ok(line.trim_end().to_string())
}
fn check_relay_error(line: &str) -> anyhow::Result<()> {
if let Some(err) = line.strip_prefix("ERROR ") {
anyhow::bail!("Relay error: {}", err);View on GitHub (pinned to 8600b91f42)