nautechsystems/nautilus_trader · error · anyhow::Error

Binance Spot data teardown failed: {}

Error message

Binance Spot data teardown failed: {}

What it means

Raised in `teardown_partial_connect` of the Binance Spot data client when one or more teardown/shutdown tasks (e.g. websocket disconnections, stream shutdowns) fail while cleaning up a partially established or closing connection. The client accumulates each failure message in `shutdown_errors`, marks itself disconnected, and bails with all messages joined by '; '. It signals that a disconnect or partial connect cleanup did not fully succeed, though the client is still flagged offline.

Source

Thrown at crates/adapters/binance/src/spot/data.rs:341

    }

    async fn teardown_partial_connect(&mut self) -> anyhow::Result<()> {
        self.session_tasks.begin_shutdown();
        self.command_tasks.begin_shutdown();
        self.ws_client.begin_shutdown();
        if let Err(e) = self.ws_client.close().await {
            self.shutdown_errors
                .push(format!("WebSocket close failed: {e}"));
        }

        if let Err(e) = self.finish_tasks().await {
            self.shutdown_errors.push(e.to_string());
        }
        self.is_connected.store(false, Ordering::Release);

        if !self.shutdown_errors.is_empty() {
            let errors = std::mem::take(&mut self.shutdown_errors);
            anyhow::bail!("Binance Spot data teardown failed: {}", errors.join("; "));
        }
        Ok(())
    }

    #[expect(clippy::too_many_arguments)]
    async fn refresh_instrument_catalog(
        http: &BinanceSpotHttpClient,
        provider: &crate::config::BinanceInstrumentProviderConfig,
        us: bool,
        instruments_cache: &Arc<AtomicMap<InstrumentId, InstrumentAny>>,
        status_cache: &Arc<AtomicMap<InstrumentId, MarketStatusAction>>,
        ws: &SpotWsClient,
        sender: &tokio::sync::mpsc::UnboundedSender<DataEvent>,
        clock: &'static AtomicTime,
        emit_status_changes: bool,
    ) -> anyhow::Result<Vec<InstrumentAny>> {
        let instruments = http
            .request_instruments_with_config(provider, us)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the joined messages after the prefix to identify which teardown step(s) failed; the client is already marked disconnected so reconnect via `connect()` is usually safe
  2. Check network/proxy reachability to Binance endpoints (api.binance.com, ws streams) at the time of teardown
  3. Increase any disconnect/shutdown timeout in the adapter config so slow closes are not aborted
  4. Retry disconnect once; transient network errors during close are common and often succeed on retry
  5. If errors persist on every disconnect, enable debug logging and report the specific failing shutdown task

Example fix

// before
data_client.disconnect().await.unwrap();
// after
if let Err(e) = data_client.disconnect().await {
    log::warn!("Binance Spot data teardown issue (client still disconnected): {e:#}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before disconnecting, confirm network reachability
// ping Binance REST endpoint with a short timeout
let ok = tokio::time::timeout(Duration::from_secs(5), reqwest::get("https://api.binance.com/api/v3/ping")).await.is_ok();

Try / catch

match client.disconnect().await {
    Ok(()) => {},
    Err(e) if e.to_string().contains("teardown failed") => {
        // client is already flagged disconnected; log and proceed with reconnect
        log::warn!("teardown error (non-fatal): {e:#}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `disconnect()` (or a `connect()` that fails partway and runs cleanup via `prepare_task_groups`) while websocket/stream shutdown tasks return errors; each failed shutdown pushes `e.to_string()` into `shutdown_errors`, and if non-empty the joined message is raised.

Common situations: Network outage or proxy drop during disconnect causing ws close to fail; Binance REST 4xx/5xx on session-termination calls; timeouts when closing streams on a slow connection; cancelling `connect()` mid-way so cleanup tasks run against half-initialized state.

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