nautechsystems/nautilus_trader · critical

failed to connect Binance Futures public WebSocket: {e}

Error message

failed to connect Binance Futures public WebSocket: {e}

What it means

Raised during `connect()` when the second WebSocket — the Binance Futures public market-data client — fails to connect, immediately after the market client succeeded. The underlying error is wrapped with anyhow and logged at ERROR level (`Binance Futures public WebSocket connection failed: {e:?}`). A failure here still fails the entire data client connect, leaving the node with no streams even though the first socket opened.

Source

Thrown at crates/adapters/binance/src/futures/data.rs:1540

            &self.ws_client,
            &self.ws_public_client,
            &self.data_sender,
            self.clock,
            false,
        )
        .await?;

        log::info!("Connecting to Binance Futures market WebSocket...");
        self.ws_client.connect().await.map_err(|e| {
            log::error!("Binance Futures market WebSocket connection failed: {e:?}");
            anyhow::anyhow!("failed to connect Binance Futures market WebSocket: {e}")
        })?;
        log::info!("Binance Futures market WebSocket connected");

        log::info!("Connecting to Binance Futures public WebSocket...");
        self.ws_public_client.connect().await.map_err(|e| {
            log::error!("Binance Futures public WebSocket connection failed: {e:?}");
            anyhow::anyhow!("failed to connect Binance Futures public WebSocket: {e}")
        })?;
        log::info!("Binance Futures public WebSocket connected");

        // Spawn market stream handler
        let stream = self.ws_client.stream();
        let sender = self.data_sender.clone();
        let insts = self.instruments.clone();
        let ws_insts = self.ws_client.instruments_cache();
        let buffers = self.book_buffers.clone();
        let book_subs = self.book_subscriptions.clone();
        let l1_book_subs = self.l1_book_subscriptions.clone();
        let force_order_refs = self.force_order_refs.clone();
        let ticker_refs = self.ticker_refs.clone();
        let force_order_all_market_refs = self.force_order_all_market_refs.clone();
        let force_order_all_market_stream_active =
            self.force_order_all_market_stream_active.clone();
        let book_epoch = self.book_epoch.clone();
        let http = self.http_client.clone();

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Inspect the wrapped `{e}` to distinguish timeout vs handshake rejection vs DNS failure
  2. Retry the full connect with backoff — both sockets are re-established on each attempt
  3. Reduce concurrent Binance WS connections (other clients/tabs/scripts) if hitting connection limits
  4. If persistent, verify the public stream host resolves and a plain TLS connection to port 443 succeeds from the same host

Example fix

# before: no tolerance for the second handshake failing
await node.run()  # raises: failed to connect Binance Futures public WebSocket: {e}

# after: backoff around the whole connect sequence (both sockets)
for attempt in range(6):
    try:
        await node.run()
        break
    except Exception as e:
        if 'failed to connect Binance Futures' not in str(e):
            raise
        await asyncio.sleep(min(2 ** attempt, 30))
Defensive patterns

Strategy: retry

Validate before calling

import socket

def binance_ws_reachable(host: str = 'fstream.binance.com', port: int = 443, timeout: float = 5.0) -> bool:
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except OSError:
        return False

Try / catch

# public client connects right after the market client; retry the whole sequence
for attempt in range(6):
    try:
        await node.run()
        break
    except Exception as e:
        if 'failed to connect Binance Futures public WebSocket' not in str(e):
            raise
        await asyncio.sleep(min(2 ** attempt, 30))
else:
    raise RuntimeError('Binance Futures public WebSocket unreachable after retries')

Prevention

When it happens

Trigger: Same connect sequence as the market client, but the public stream host fails: transient network drop between the two handshakes, firewall/DNS issues specific to the public stream endpoint, Binance connection-limit or rate-limit rejections when too many sockets open rapidly, or region-blocked IPs.

Common situations: Flaky networking where the first connect succeeds and the second times out; hitting Binance's per-IP WebSocket connection limits during reconnect storms; CI environments with restricted egress; testnet public stream endpoints under maintenance.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/fefeab91476dae6e. Report an issue: GitHub.