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.

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)

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.