nautechsystems/nautilus_trader · error · TransportError::Io(std::io::Error)

connection timed out after {}s

Error message

connection timed out after {}s

What it means

The connection future (using the selected backend and optional proxy) is raced against the configured connect timeout; when the timeout wins, the client returns a `ErrorKind::TimedOut` error with the elapsed seconds, indicating the WebSocket endpoint did not complete the handshake in time.

Source

Thrown at crates/network/src/websocket/client.rs:420

                    rate_limit
                        .limiter
                        .await_keys_ready(Some(&rate_limit.keys))
                        .await;
                }

                // Bound only the dial: the connection rate-limit wait has its own venue timing
                dst::time::timeout(
                    connect_timeout,
                    Box::pin(Self::connect_with_server(
                        &config.url,
                        config.headers.clone(),
                        config.backend,
                        config.proxy_url.as_deref(),
                    )),
                )
                .await
                .unwrap_or_else(|_| {
                    Err(TransportError::Io(std::io::Error::new(
                        std::io::ErrorKind::TimedOut,
                        format!(
                            "connection timed out after {}s",
                            connect_timeout.as_secs_f64()
                        ),
                    )))
                })
            })
        };
        let classify = |error: &TransportError| {
            let retryable = is_retryable_initial_connect_error(error);
            let attempt = attempt.load(Ordering::Relaxed);
            if retryable && attempt < max_attempts && !cancellation_token.is_cancelled() {
                log::warn!(
                    "WebSocket connection attempt {attempt}/{max_attempts} to {REDACTED} failed: {error}"
                );
            }
            retryable

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the endpoint URL and port are correct and reachable (`curl`/`wscat` to the URL).
  2. Increase `connect_timeout` (e.g. to 10–30s) in the WebSocket config.
  3. If `proxy_url` is set, test the proxy independently; remove or fix it if it is the bottleneck.
  4. Add retry-with-backoff around connect for transient network issues.

Example fix

// before
let config = WebSocketConfig { connect_timeout: Duration::from_millis(200), .. };
// after
let config = WebSocketConfig { connect_timeout: Duration::from_secs(20), .. };
Defensive patterns

Strategy: retry

Validate before calling

// sanity-check endpoint and timeout before connecting
assert!(url.starts_with("wss://") || url.starts_with("ws://"));
assert!(config.connect_timeout >= Duration::from_secs(1));

Try / catch

match connect_url_with_handler(url, handler, config).await {
    Err(e) if e.to_string().contains("connection timed out") => {
        tokio::time::sleep(backoff.next()).await;
        // retry connect
    }
    Err(e) => return Err(e),
    Ok(c) => c,
}

Prevention

When it happens

Trigger: Calling `connect_url_with_handler` when the remote WebSocket endpoint is unreachable, hangs during TLS/handshake, a configured `proxy_url` is down or slow, or `connect_timeout` is set lower than realistic network latency.

Common situations: Data-feed endpoints that silently drop packets, wrong port/host in config, broken proxy configuration, network throttling, or sub-second timeouts used in low-latency setups.

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.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/5b3c82c2675790a5. Report an issue: GitHub.