tonhowtf/omniget · error

Failed to connect to relay

Error message

Failed to connect to relay {}: {}

What it means

connect_relay surfaces the underlying OS error when TcpStream::connect to the relay fails immediately (the message interpolates the relay address and the io::Error). This is the non-timeout failure path: the connect attempt itself returned an error, e.g. connection refused, DNS resolution failure, or no route to host.

Solutions

  1. Read the embedded io::Error: 'refused' means start the relay service; 'resolve' means fix DNS/hostname in relay_addr().
  2. Confirm the relay is listening on the configured port (ss -ltn / netstat on the relay host).
  3. Validate relay_addr() output and correct any misconfigured host or port.
  4. Test connectivity manually: nc -vz <relay-host> <port>.
  5. Retry if the failure was transient (network flap); consider adding automatic retry in the caller.

Example fix

// before
.map_err(|e| anyhow!("Failed to connect to relay {}: {}", addr, e))?;
// after
.map_err(|e| {
    tracing::error!("relay connect failed addr={} err={:?}", addr, e);
    anyhow!("Failed to connect to relay {}: {} (is the relay running and reachable?)", addr, e)
})?;
Defensive patterns

Strategy: retry

Validate before calling

// Rust: probe the relay endpoint before the transfer
async fn can_reach_relay(addr: &str) -> Result<(), String> {
    tokio::net::TcpStream::connect(addr)
        .await
        .map(|_| ())
        .map_err(|e| format!("relay {} unreachable: {}", addr, e))
}

Try / catch

if let Err(e) = connect_relay().await {
    tracing::error!("relay connect failed: {e:#}");
    // parse embedded io::Error kind: ConnectionRefused -> start relay; NotFound/Resolve -> fix DNS
    return Err(anyhow!("Relay unavailable, please try again later"));
}

Prevention

When it happens

Trigger: TcpStream::connect(&addr) returns Err — relay port not listening (connection refused), hostname in relay_addr() does not resolve, or OS-level network error (no route, network unreachable).

Common situations: Relay service not started on the host; typo in relay host/port; DNS outage; connecting to localhost relay that isn't running; wrong port after a config change.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/bfdc032ab9ace71e. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/src/platforms/p2p/mod.rs:32

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)