{"record":{"id":"f2e801c5f9ccd257","repo":"tonhowtf/omniget","slug":"connection-to-relay-timed-out-10s","errorCode":null,"errorMessage":"Connection to relay timed out (10s)","messagePattern":"Connection to relay timed out \\(10s\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/platforms/p2p.rs","lineNumber":29,"sourceCode":"use tokio_util::sync::CancellationToken;\n\nuse crate::models::media::{DownloadOptions, DownloadResult, MediaInfo, MediaType, VideoQuality};\nuse crate::platforms::traits::PlatformDownloader;\n\nconst CHUNK_SIZE: usize = 64 * 1024;\n\nfn relay_addr() -> String {\n    std::env::var(\"OMNIGET_RELAY\").unwrap_or_else(|_| \"relay.tonho.wtf:9009\".to_string())\n}\n\nasync fn connect_relay() -> anyhow::Result<TcpStream> {\n    let addr = relay_addr();\n    let stream = tokio::time::timeout(\n        std::time::Duration::from_secs(10),\n        TcpStream::connect(&addr),\n    )\n    .await\n    .map_err(|_| anyhow!(\"Connection to relay timed out (10s)\"))?\n    .map_err(|e| anyhow!(\"Failed to connect to relay {}: {}\", addr, e))?;\n    Ok(stream)\n}\n\nasync fn read_line(\n    reader: &mut BufReader<tokio::io::ReadHalf<TcpStream>>,\n) -> anyhow::Result<String> {\n    let mut line = String::new();\n    let n = reader.read_line(&mut line).await?;\n    if n == 0 {\n        anyhow::bail!(\"Relay closed connection unexpectedly\");\n    }\n    Ok(line.trim_end().to_string())\n}\n\nfn check_relay_error(line: &str) -> anyhow::Result<()> {\n    if let Some(err) = line.strip_prefix(\"ERROR \") {\n        anyhow::bail!(\"Relay error: {}\", err);","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/p2p.rs#L11-L47","documentation":"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 ...'.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet stream = tokio::time::timeout(\n    std::time::Duration::from_secs(10),\n    TcpStream::connect(&addr),\n).await.map_err(|_| anyhow!(\"Connection to relay timed out (10s)\"))?...\n// after\nconst RELAY_TIMEOUT: Duration = Duration::from_secs(10);\nlet mut attempt = 0;\nlet stream = loop {\n    attempt += 1;\n    match tokio::time::timeout(RELAY_TIMEOUT, TcpStream::connect(&addr)).await {\n        Ok(res) => break res.map_err(|e| anyhow!(\"Failed to connect to relay {}: {}\", addr, e))?,\n        Err(_) if attempt < 3 => tokio::time::sleep(Duration::from_secs(2 * attempt)).await,\n        Err(_) => return Err(anyhow!(\"Connection to relay {} timed out after {} attempts\", addr, attempt)),\n    }\n};","handlingStrategy":"retry","validationCode":"// Rust: probe relay reachability before starting a relay-based transfer\nasync fn relay_reachable() -> bool {\n    let addr = relay_addr();\n    tokio::time::timeout(Duration::from_secs(3), TcpStream::connect(&addr))\n        .await\n        .map(|r| r.is_ok())\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match p2p_download(opts).await {\n    Err(e) if e.to_string().contains(\"Connection to relay timed out\") => {\n        // relay unreachable; retry with backoff or switch to direct/LAN transfer\n        tokio::time::sleep(Duration::from_secs(5)).await;\n        p2p_download(opts).await\n    }\n    other => other,\n}","preventionTips":["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"],"tags":["network","tcp","timeout","p2p"],"backgroundTag":"request-timeout","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}