nautechsystems/nautilus_trader · error

Betfair data shutdown failed: {}

Error message

Betfair data shutdown failed: {}

What it means

When a Betfair data client disconnects or fails during connect, teardown_partial_connect collects errors from shutting down individual tasks/streams into self.shutdown_errors. If any were recorded, teardown bails with this aggregated message so partial-connect failures surface instead of being silently dropped.

Source

Thrown at crates/adapters/betfair/src/data.rs:297

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

        if self.stream_client.is_none()
            && self.race_stream_client.is_none()
            && self.cricket_stream_client.is_none()
        {
            self.stream_shutdowns.lock().clear();
        }

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

    fn create_stream_handler(
        data_sender: tokio::sync::mpsc::UnboundedSender<DataEvent>,
        instruments: Arc<AtomicMap<InstrumentId, InstrumentAny>>,
        currency: Currency,
        min_notional: Option<Money>,
        reconnect_tx: tokio::sync::mpsc::UnboundedSender<()>,
        clock: &'static AtomicTime,
    ) -> StreamMessageHandler {
        // Track cumulative traded volumes per (instrument_id, price) to compute
        // incremental trade sizes. Betfair `trd` fields report totals, not deltas.
        let traded_volumes: Arc<Mutex<AHashMap<(InstrumentId, Decimal), Decimal>>> =
            Arc::new(Mutex::new(AHashMap::new()));
        let has_initial_connection = Arc::new(AtomicBool::new(false));

        Arc::new(move |msg: StreamMessage| {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the joined error list in the message to identify which task failed and fix the root cause
  2. Ensure disconnect() is awaited and the runtime is not shutting down mid-await
  3. Retry connect after a clean disconnect; report if a specific task reliably fails teardown
Defensive patterns

Strategy: try-catch

Try / catch

match client.disconnect().await {
    Ok(()) => {},
    Err(e) if e.to_string().starts_with("Betfair data shutdown failed") => {
        warn!("partial teardown: {e:#}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: disconnect() or a failed connect()/prepare_task_groups path where one or more background tasks (stream reader, heartbeats, subscriptions) fail to cancel/join cleanly, populating shutdown_errors.

Common situations: Network drop mid-connect leaving a task unresponsive; task panics during teardown; calling disconnect while the stream handler is blocked on I/O.

Related errors


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