nautechsystems/nautilus_trader · warning · anyhow::Error

Binance Futures shutdown failed

Error message

Binance Futures shutdown failed: {}

What it means

During disconnect, the client collects errors from individual shutdown steps into shutdown_errors; if any accumulated, it joins them and bails with 'Binance Futures shutdown failed' after already marking itself disconnected. The client is down, but some cleanup step(s) failed.

Solutions

  1. Read the joined error list in the message to identify which teardown step failed.
  2. Confirm the client is actually disconnected (core.set_disconnected runs before the bail) — a reconnect can proceed.
  3. Fix the underlying network/proxy issue before the next shutdown/reconnect cycle.
  4. Treat listen-key deletion failures as benign if the key expires automatically in 24h.
Defensive patterns

Strategy: try-catch

Try / catch

match client.disconnect().await {
    Err(e) if e.to_string().starts_with("Binance Futures shutdown failed") => {
        log::warn!("shutdown partially failed (client already marked disconnected): {e}");
        // safe to reconnect
    }
    other => other?,
}

Prevention

When it happens

Trigger: Any component's shutdown path (WS streams, user-data stream, HTTP session teardown) pushes into shutdown_errors during disconnect(), commonly due to network drops while closing sockets or a listen-key delete failing.

Common situations: Network already down when disconnect is called; WS connection already closed by the server so the close handshake errors; timeout while deleting the Binance listen key.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/acc2c69cf419e525. Report an issue: GitHub.

Appendix: source

Thrown at crates/adapters/binance/src/futures/execution.rs:2172

        if let Err(e) = self
            .close_listen_key_slot(
                &self.recovery_listen_key,
                "failed to close recovery listen key",
            )
            .await
        {
            self.shutdown_errors.push(e.to_string());
        }

        if let Err(e) = self.await_pending_tasks().await {
            self.shutdown_errors.push(e.to_string());
        }

        self.core.set_disconnected();

        if !self.shutdown_errors.is_empty() {
            let shutdown_errors = std::mem::take(&mut self.shutdown_errors);
            anyhow::bail!(
                "Binance Futures shutdown failed: {}",
                shutdown_errors.join("; ")
            );
        }
        log::info!("Disconnected: client_id={}", self.core.client_id);
        Ok(())
    }

    async fn generate_order_status_report(
        &self,
        cmd: &GenerateOrderStatusReport,
    ) -> anyhow::Result<Option<OrderStatusReport>> {
        let Some(instrument_id) = cmd.instrument_id else {
            log::warn!("generate_order_status_report requires instrument_id: {cmd}");
            return Ok(None);
        };
        let Some(instrument) = self.http_client.instrument_reconciliation(&instrument_id) else {
            if self.is_instrument_out_of_scope(instrument_id) {

View on GitHub (pinned to 18893faf8b)