rathole-org/rathole · error

No available data channels

Error message

No available data channels

What it means

run_udp_connection_pool pulls a ready data channel from an internal mpsc channel to forward UDP traffic. If the channel is closed (all senders dropped) or empty when `recv().await` completes, it means no data channels were established, so UDP forwarding cannot proceed and the error is raised at src/server.rs:687.

Solutions

  1. Ensure the client is running and successfully establishes data channels before/in tandem with UDP traffic.
  2. Check logs on the client side for data-channel connection failures (TLS/noise/websocket handshake errors).
  3. Verify network/firewall rules allow the data channel connections between client and server.
  4. Reconnect the client or restart the UDP session so the pool gets a fresh data channel.
Defensive patterns

Strategy: retry

Try / catch

match run_udp_connection_pool(...).await {
    Err(e) if e.to_string().contains("No available data channels") => {
        warn!("data channel pool empty; retrying after reconnect");
        tokio::time::sleep(Duration::from_secs(2)).await;
        // re-establish data channels then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: A UDP session is requested on the server but the pool's data_ch_rx receiver yields None — typically because no client-side data channels connected yet, or all data channel tasks exited/closed the channel.

Common situations: Client disconnected while a UDP session (e.g. DNS forwarding) is still active; network interruption killed all data channel connections; server started but no client ever established the data channel pool; firewall/NAT blocking the data channel connections.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of rathole-org/rathole@a292f7ed54 (2026-09-07). Data as JSON: /api/errors/34f2a1abb6a28649. Report an issue: GitHub.

Appendix: source

Thrown at src/server.rs:687

        listen_backoff(),
        || async { Ok(UdpSocket::bind(&bind_addr).await?) },
        |e, duration| {
            warn!("{:#}. Retry in {:?}", e, duration);
        },
        &mut shutdown_rx,
    )
    .await
    .with_context(|| "Failed to listen for the service")?;

    info!("Listening at {}", &bind_addr);

    let cmd = bincode::serialize(&DataChannelCmd::StartForwardUdp).unwrap();

    // Receive one data channel
    let mut conn = data_ch_rx
        .recv()
        .await
        .ok_or_else(|| anyhow!("No available data channels"))?;
    write_and_flush(&mut conn, &cmd).await?;

    let mut buf = [0u8; UDP_BUFFER_SIZE];
    loop {
        tokio::select! {
            // Forward inbound traffic to the client
            val = l.recv_from(&mut buf) => {
                let (n, from) = val?;
                UdpTraffic::write_slice(&mut conn, from, &buf[..n]).await?;
            },

            // Forward outbound traffic from the client to the visitor
            hdr_len = conn.read_u8() => {
                let t = UdpTraffic::read(&mut conn, hdr_len?).await?;
                l.send_to(&t.data, t.from).await?;
            }

            _ = shutdown_rx.recv() => {

View on GitHub (pinned to a292f7ed54)