nautechsystems/nautilus_trader · error · anyhow::Error

Binance Spot public JSON stream pool shutdown began during…

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.

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.

Appendix: 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)