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}"
);
}
retryableView on GitHub (pinned to 18893faf8b)
Solutions
- Verify the endpoint URL and port are correct and reachable (`curl`/`wscat` to the URL).
- Increase `connect_timeout` (e.g. to 10–30s) in the WebSocket config.
- If `proxy_url` is set, test the proxy independently; remove or fix it if it is the bottleneck.
- 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
- Validate the endpoint with a quick manual handshake (wscat/curl) before wiring it up.
- Keep connect_timeout well above worst-case TLS handshake time.
- Test proxy_url separately; a dead proxy presents exactly as this timeout.
- Wrap connects in retry-with-backoff for transient network conditions.
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.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Lighter WebSocket initial connection timeout after {} second
- reconnection timed out after {}s
- Binance Futures data teardown failed: {}
- Binance Spot data teardown failed: {}
- subscription confirmation failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5b3c82c2675790a5.
Report an issue: GitHub.