nautechsystems/nautilus_trader · warning

failed to finish Binance Futures data command tasks: {e}

Error message

failed to finish Binance Futures data command tasks: {e}

What it means

During Binance Futures data client shutdown, `finish_tasks` waits for both the session and command task groups to finish (1s/2s timeouts). If the command task group's `finish_shutdown` returns an error, it is collected into a combined message and bailed. This signals command-related WebSocket/subscription tasks did not shut down cleanly.

Source

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

                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),
            self.command_tasks
                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),
        );
        let mut errors = Vec::new();
        if let Err(e) = session_result {
            errors.push(format!(
                "failed to finish Binance Futures data session tasks: {e}"
            ));
        }

        if let Err(e) = command_result {
            errors.push(format!(
                "failed to finish Binance Futures data command tasks: {e}"
            ));
        }

        if !errors.is_empty() {
            anyhow::bail!(errors.join("; "));
        }
        Ok(())
    }

    async fn prepare_task_groups(&mut self) -> anyhow::Result<()> {
        if !self.session_tasks.is_open() || !self.command_tasks.is_open() {
            self.teardown_partial_connect().await?;
            self.session_tasks
                .start_generation()
                .context("failed to start Binance Futures data session task generation")?;
            self.command_tasks
                .start_generation()
                .context("failed to start Binance Futures data command task generation")?;
            self.cancellation_token = self.session_tasks.cancellation_token();
        }
        Ok(())
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check logs for the paired 'failed to finish Binance Futures data session tasks' message to identify which task group hung
  2. Ensure the network connection is healthy and the WebSocket close is not blocked by a hung socket before disconnecting
  3. Avoid overlapping connect/disconnect calls; let the previous shutdown complete
  4. Retry the disconnect; the teardown sets is_connected=false regardless, so state is consistent
  5. Upgrade the adapter if timeouts are consistently too short for your latency profile

Example fix

// before
client.disconnect();
client.subscribe(cmd); // overlapping work during shutdown
// after
client.disconnect().await?; // ensure teardown completes first
client.subscribe(cmd);
Defensive patterns

Strategy: try-catch

Validate before calling

assert!(session_tasks.is_open() && command_tasks.is_open(), "task groups must be open before disconnect");

Try / catch

match client.disconnect().await {
    Err(e) if e.to_string().contains("teardown failed") => log::warn!("task shutdown issue: {e}"),
    Err(e) => return Err(e),
    Ok(()) => Ok(()),
}

Prevention

When it happens

Trigger: Calling teardown_partial_connect (from prepare_task_groups, connect, or disconnect) while command tasks (subscription/unsubscription futures) hang or fail to complete within the 1s drain/2s timeout, or the underlying task join fails (e.g. WebSocket already in a broken state).

Common situations: Network partitions during shutdown, disconnect/reconnect races, calling disconnect while subscription commands are still in flight, or repeated connect/disconnect cycles that left task groups in a bad state.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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