nautechsystems/nautilus_trader · critical

failed to connect Binance Futures private WebSocket

Error message

failed to connect Binance Futures private WebSocket

What it means

During user-data-stream recovery, `build_and_connect_user_stream` creates a fresh private WebSocket client for the Binance Futures listen-key stream and awaits `ws_client.connect()`. If the connect future resolves with an error (transport-level failure), the error is swallowed for logging and replaced with this generic anyhow error so `recover_with_retry` will re-attempt. It means the recovered private stream could not be established.

Solutions

  1. Check network connectivity to the Binance Futures WS endpoint (DNS, TLS, firewall/proxy); retry — `recover_with_retry` already schedules further attempts.
  2. Verify API key validity and that a valid listen-key was created (a bad key fails the stream after connect).
  3. Confirm no regional/IP restriction applies (Binance blocks some jurisdictions/IPs).
  4. Inspect the preceding `log::error!` output and enable debug logging for the underlying transport for the concrete cause.
Defensive patterns

Strategy: retry

Try / catch

// Recovery already retries via recover_with_retry; add bounded outer handling
match stream.recover_with_retry(max_attempts).await {
    Ok(()) => {},
    Err(e) if e.to_string().contains("failed to connect Binance Futures private WebSocket") => {
        log::error!("recovery connect failed after retries: {e}; check network/listen-key");
        // escalate: restart data engine or alert operator
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: `recover_user_data_stream` (via `recover_with_retry`, typically after a -1125 listen-key invalidation/expiry or dropped connection) calls `connect`, and the WebSocket handshake fails — DNS failure, TLS error, proxy blocking wss://, or Binance endpoint unreachable.

Common situations: Network outage or firewall/proxy blocking the Binance WS endpoint during recovery; Binance regional endpoint blocked from your host (e.g. restricted jurisdiction); transient DNS failure; listen-key recreated but network flap at the same time.

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/e74474786c8e0e03. Report an issue: GitHub.

Appendix: source

Thrown at crates/adapters/binance/src/futures/websocket/streams/recovery.rs:123

        Some(BINANCE_WS_HEARTBEAT_SECS),
        params.transport_backend,
    )
    .context("failed to construct Binance Futures private WebSocket client")?
    .with_proxy(
        params
            .proxy_url
            .as_ref()
            .map(|value| value.expose_secret().to_owned()),
    )
    .with_socket_control(
        params.socket_factory.clone(),
        "binance-futures-user-streams",
    );

    log::debug!("Connecting to Binance Futures user data stream...");
    ws_client.connect().await.map_err(|_| {
        log::error!("Binance Futures private WebSocket connection failed");
        anyhow::anyhow!("failed to connect Binance Futures private WebSocket")
    })?;
    log::debug!("Connected to Binance Futures user data stream");

    Ok(ws_client)
}

/// Long-lived task that consumes recovery signals and runs
/// [`recover_user_data_stream`] with retry-on-failure semantics.
pub(crate) async fn run_recovery_driver<F>(
    ctx: RecoveryCtx,
    mut rx: tokio::sync::mpsc::UnboundedReceiver<()>,
    cancel: CancellationToken,
    dispatch_fn: F,
) where
    F: Fn(BinanceFuturesWsStreamsMessage, &DispatchCtx, &tokio::sync::mpsc::UnboundedSender<()>)
        + Send
        + Sync
        + Clone

View on GitHub (pinned to 18893faf8b)