xai-org/grok-build · error
WebSocket connection timed out after {} seconds
Error message
WebSocket connection timed out after {} seconds What it means
connect_to_relay wraps the WebSocket handshake in tokio::time::timeout with CONNECT_TIMEOUT_SECS. If the handshake future is still pending when the timeout elapses, the elapsed branch bails with "WebSocket connection timed out after {N} seconds".
Source
Thrown at crates/codegen/xai-grok-shell/src/agent/relay.rs:450
Ok((ws, resp))
} else {
// The default connector never sees the shared trust config.
let connector =
tokio_tungstenite::Connector::Rustls(xai_grok_extra_ca::rustls_client_config());
connect_async_tls_with_config(req, None, false, Some(connector))
.await
.map_err(|e| anyhow::Error::from(e).context("WebSocket connection failed"))
}
}) => {
match result {
Ok(Ok((ws, resp))) => {
if let Some(proto) = resp.headers().get("Sec-WebSocket-Protocol") {
info!(subprotocol = ?proto, "WS subprotocol negotiated");
}
Ok(ws)
}
Ok(Err(e)) => Err(e),
Err(_) => anyhow::bail!("WebSocket connection timed out after {} seconds", CONNECT_TIMEOUT_SECS),
}
}
}
}
/// Run a single WebSocket session, handling messages until disconnection.
pub(crate) async fn run_websocket_session<S>(
ws: tokio_tungstenite::WebSocketStream<S>,
to_agent_tx: &mpsc::UnboundedSender<String>,
from_agent_rx: &mut mpsc::UnboundedReceiver<String>,
cancel: &CancellationToken,
) -> anyhow::Result<SessionEndReason>
where
S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + 'static,
{
run_websocket_session_with_liveness(
ws,
to_agent_tx,
from_agent_rx,View on GitHub (pinned to bc7f02eddd)
Solutions
- Verify network connectivity to the relay host/port (curl or ping the host).
- Check firewall/VPN rules — silent drops (no RST) are the usual cause of a full-timeout rather than a refused error.
- Confirm the relay URL/origin configuration points at the correct host.
- Retry with backoff; if behind a proxy, test whether the proxy is the bottleneck (also see proxy CONNECT errors).
Example fix
// before
let ws = connect_to_relay(&config, &cancel, proxy).await?;
// after
let ws = retry_with_backoff(3, || async {
connect_to_relay(&config, &cancel, proxy).await
}).await?; Defensive patterns
Strategy: retry
Try / catch
match connect_to_relay(&config, &cancel, proxy).await {
Err(e) if e.to_string().contains("timed out after") => {
// retry with backoff, then surface a clear connectivity error
retry_with_backoff(3, || connect_to_relay(&config, &cancel, proxy)).await
.context("relay unreachable: check network/firewall and relay host")
}
other => other,
} Prevention
- Verify relay host/port reachability before starting sessions in restricted networks
- Check firewall/VPN rules — silent packet drops cause full timeouts rather than refused errors
- Retry with exponential backoff for transient network issues
- Validate the relay origin configuration points at the correct host
When it happens
Trigger: The WS handshake (optionally via proxy CONNECT + TLS + tokio-tungstenite handshake) does not complete within CONNECT_TIMEOUT_SECS — the timeout Err(_) arm fires.
Common situations: Relay host unreachable (packets silently dropped by firewall); DNS resolving but routing black-holed; very slow network or heavily loaded proxy; wrong relay origin/host configured.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- wait failed: {body}
- Connection cancelled
- GCS download stalled: no data received for {chunk_timeout:?}
- {} failed: {}
- Upload timed out after {}s
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/f4fbbff75ffbef58.
Report an issue: GitHub.