nautechsystems/nautilus_trader · error · anyhow::Error

Failed to connect Spot public JSON WS: {e}

Error message

Failed to connect Spot public JSON WS: {e}

What it means

create_connection() builds the WebSocket client (URL, handlers, quotas) and awaits .connect(). This error wraps any failure from that underlying WebSocket connection attempt, e.g. DNS failure, TCP/TLS error, HTTP upgrade rejection, or connection timeout to Binance's Spot WS endpoint.

Source

Thrown at crates/adapters/binance/src/spot/websocket/public_json/client.rs:551

            .zip(self.socket_endpoint.as_ref())
            .map(|(factory, endpoint)| {
                let endpoint = if slot_index == 0 {
                    endpoint.clone()
                } else {
                    format!("{endpoint}-{slot_index}")
                };
                factory.control(endpoint)
            });
        let client = WebSocketClient::builder()
            .config(config)
            .message_handler(raw_handler)
            .ping_handler(ping_handler)
            .keyed_quotas(keyed_quotas)
            .default_quota(*BINANCE_WS_CONNECTION_QUOTA)
            .maybe_state_sink(socket_control.as_ref().map(SocketControl::sink))
            .connect()
            .await
            .map_err(|e| anyhow::anyhow!("Failed to connect Spot public JSON WS: {e}"))?;

        let connection_mode = client.connection_mode_atomic();
        let reconnect_handle = client.reconnect_handle();
        let subscriptions_state = SubscriptionState::new('@');
        let cancellation_token = CancellationToken::new();

        let (cmd_tx, cmd_rx) = tokio::sync::mpsc::unbounded_channel();

        let (bytes_tx, bytes_rx) = tokio::sync::mpsc::unbounded_channel::<Vec<u8>>();

        let mut bytes_task = TaskSlot::new();
        if let Err(e) = bytes_task.spawn(async move {
            let mut raw_rx = raw_rx;
            while let Some(msg) = raw_rx.recv().await {
                let data = match msg {
                    Message::Binary(data) => data.to_vec(),
                    Message::Text(text) => text.as_bytes().to_vec(),
                    Message::Close(_) => break,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry with backoff — most failures are transient network issues; the pool's reconnect machinery may already handle it on later subscribe attempts.
  2. Verify network reachability to the WS host (test wss://stream.binance.com:9443 from the deployment environment).
  3. Check the embedded {e} for the root cause (DNS vs TLS vs HTTP status) and fix accordingly (DNS config, proxy settings, VPN/region).
  4. Confirm the configured URL is the correct Binance Spot WS endpoint and not blocked in your jurisdiction.

Example fix

// before
client.connect().await?; // hard fail on transient network blip

// after
for attempt in 0..5 {
    match client.connect().await {
        Ok(_) => break,
        Err(e) if attempt < 4 => {
            log::warn!("connect failed ({e}), retrying");
            tokio::time::sleep(Duration::from_secs(2u64.pow(attempt))).await;
        }
        Err(e) => return Err(e),
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// preflight reachability check
// tokio::net::TcpStream::connect("stream.binance.com:9443").await?;

Try / catch

match client.connect().await {
    Err(e) if e.to_string().contains("Failed to connect Spot public JSON WS") => {
        log::warn!("WS connect failed, retrying with backoff: {e}");
        tokio::time::sleep(Duration::from_secs(5)).await;
        // retry
    }
    r => r,
}

Prevention

When it happens

Trigger: The underlying ws client's connect() returns Err while opening a new pool slot connection: unreachable host, refused connection, TLS failure, invalid URL, or rejected handshake (proxy/firewall, 4xx/5xx from the endpoint).

Common situations: No internet or DNS outage; corporate proxy or firewall blocking wss://stream.binance.com; Binance geo-blocking (e.g. restricted regions); transient Binance outage; wrong stream URL configured.

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 nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/4d77079a39398202. Report an issue: GitHub.