nautechsystems/nautilus_trader · error · anyhow::Error

Binance Spot public JSON stream pool shutdown began during s

Error message

Binance Spot public JSON stream pool shutdown began during subscribe

What it means

The pool observed its shutdown flag while a subscribe() call was in progress; the client rolled back by closing connections and returned this error because rollback succeeded. It guarantees no new subscriptions are added to a pool that is being torn down.

Source

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

            };

            if remaining_capacity >= new_streams.len() || slot_count >= MAX_CONNECTIONS {
                break;
            }

            let new_slot = self.create_connection(slot_count).await?;
            let (slot_count, shutdown) = {
                let mut slots = self.slots.lock();
                let shutdown = self.signal.load(Ordering::Acquire);
                slots.push(new_slot);
                (slots.len(), shutdown)
            };

            if shutdown {
                let client = self.clone();
                let rollback = client.close_connections().await;
                return Err(match rollback {
                    Ok(()) => anyhow::anyhow!(
                        "Binance Spot public JSON stream pool shutdown began during subscribe"
                    ),
                    Err(e) => anyhow::anyhow!(
                        "Binance Spot public JSON stream pool shutdown began during subscribe; rollback failed: {e}"
                    ),
                });
            }
            log::debug!(
                "Spot JSON pool slot {} connected: url={}",
                slot_count - 1,
                self.url
            );
        }

        // Phase 3: stage assignments, send commands, then commit slot state.
        let mut slots = self.slots.lock();

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

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Await all pending subscribe() futures before calling close_connections()/shutdown.
  2. Treat this error as benign during shutdown: check the pool's shutdown state and skip retrying if teardown was intentional.
  3. Reorder component stop: cancel subscription tasks first, then shut down the pool.
  4. If rollback errors also appear, inspect handler task lifetimes so close_connections() is only called once.

Example fix

// before
client.subscribe(streams).await?; // races shutdown
client.close_connections().await;

// after
if !client.is_shutdown() {
    client.subscribe(streams).await?;
}
client.close_connections().await;
Defensive patterns

Strategy: try-catch

Validate before calling

if pool.is_shutdown() {
    return; // skip subscribe during shutdown
}

Try / catch

match client.subscribe(streams).await {
    Err(e) if e.to_string().contains("shutdown began during subscribe") => {
        log::debug!("subscribe aborted by shutdown");
    }
    Err(e) => return Err(e),
    Ok(v) => Ok(v),
}

Prevention

When it happens

Trigger: Calling subscribe() on the public JSON pool concurrently with close_connections()/shutdown; the shutdown flag is set after the subscription batching begins but before commands are dispatched.

Common situations: Stopping a data engine or actor while quote/kline subscription requests are still queued; application shutdown ordering where the market-data client is stopped before dependent subscribers finish subscribing.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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