nautechsystems/nautilus_trader · error

{errors.join("; ")}

Error message

{errors.join("; ")}

What it means

close_connections tears down all slots in the public JSON stream pool and collects per-slot disconnect errors; if any slot failed to shut down cleanly it joins them with ';' and bails. The pool did disconnect its tasks, but at least one slot's handler/bytes task ended with an error during shutdown. This is an aggregated multi-error report.

Source

Thrown at crates/adapters/binance/src/spot/websocket/public_json/client.rs:291

            {
                batch.slots.remove(index);
            }
        }

        *self.out_tx.lock() = None;
        *self.out_rx.lock() = None;

        let errors = batch
            .slots
            .iter_mut()
            .flat_map(|slot| std::mem::take(&mut slot.shutdown_errors))
            .collect::<Vec<_>>();
        batch
            .slots
            .retain(|slot| slot.handler_task.is_some() || slot.bytes_task.is_some());

        if !errors.is_empty() {
            anyhow::bail!(errors.join("; "));
        }
        log::debug!("Disconnected from Binance Spot public JSON stream pool");
        Ok(())
    }

    /// Subscribes to stream names.
    ///
    /// # Errors
    ///
    /// Returns an error if command delivery fails or if the connection pool is exhausted.
    pub async fn subscribe(&self, streams: Vec<String>) -> anyhow::Result<()> {
        let _connect_guard = self.connect_lock.lock().await;

        // Phase 1: filter already-subscribed streams (brief lock)
        let new_streams: Vec<String> = {
            let slots = self.slots.lock();

            if self.signal.load(Ordering::Acquire) {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the joined error list to identify which slot(s) failed and whether the failure is transient (network) or persistent.
  2. If transient, recreate/reconnect the client — connect() calls close_connections, so a fresh connect replaces the pool.
  3. Ensure close is not called concurrently with subscribe/unsubscribe on the same pool.
  4. If a slot task keeps failing, check stream names and connection stability; an already-dead task's error may be unavoidable at close time.
Defensive patterns

Strategy: try-catch

Try / catch

if let Err(e) = client.close().await {
    log::warn!("disconnect reported errors (may be benign during shutdown): {e:#}");
}

Prevention

When it happens

Trigger: Calling close_connections (via connect to re-connect, or explicit close) when one or more slot handler_task or bytes_task join results contain errors — e.g. a task already crashed with a WS error, or shutdown signals failed to be acknowledged.

Common situations: Reconnecting after a network drop where some slot tasks already died with errors; closing the client while Binance is unreachable; tearing down during process shutdown where tasks fail cancellation.

Related errors


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