nautechsystems/nautilus_trader · error · anyhow::Error

Spot public JSON stream pool exhausted ({MAX_CONNECTIONS} co

Error message

Spot public JSON stream pool exhausted ({MAX_CONNECTIONS} connections x {MAX_STREAMS_PER_CONNECTION} streams)

What it means

The pool has a hard capacity of MAX_CONNECTIONS WebSocket connections, each carrying at most MAX_STREAMS_PER_CONNECTION streams (Binance's limits). subscribe() failed because every existing slot is full and no free slot exists to host the new streams.

Source

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

                self.url
            );
        }

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

        if self.signal.load(Ordering::Acquire) {
            anyhow::bail!("Binance Spot public JSON stream pool is shutting down");
        }
        let mut slot_batches: Vec<(usize, Vec<String>)> = Vec::new();
        let mut slot_counts: Vec<usize> = slots.iter().map(|s| s.streams.len()).collect();

        for stream in &new_streams {
            let slot_idx = slot_counts
                .iter()
                .position(|&count| count < MAX_STREAMS_PER_CONNECTION)
                .ok_or_else(|| {
                    anyhow::anyhow!(
                        "Spot public JSON stream pool exhausted ({MAX_CONNECTIONS} connections x {MAX_STREAMS_PER_CONNECTION} streams)",
                    )
                })?;

            slot_counts[slot_idx] += 1;

            if let Some(batch) = slot_batches.iter_mut().find(|(i, _)| *i == slot_idx) {
                batch.1.push(stream.clone());
            } else {
                slot_batches.push((slot_idx, vec![stream.clone()]));
            }
        }

        for (slot_idx, batch) in &slot_batches {
            slots[*slot_idx]
                .cmd_tx
                .send(BinanceSpotPublicWsCommand::Subscribe {
                    streams: batch.clone(),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Reduce the number of simultaneously subscribed streams; unsubscribe instruments no longer needed before subscribing new ones.
  2. Split the workload across multiple pool/client instances (e.g., per asset class or shard).
  3. Check MAX_STREAMS_PER_CONNECTION/MAX_CONNECTIONS constants against current Binance limits and adjust configuration if they are outdated.
  4. Handle this error by degrading: fall back to REST polling or a reduced symbol set when the pool is exhausted.

Example fix

// before
client.subscribe(huge_stream_list).await?; // may exceed pool capacity

// after
let capacity = MAX_CONNECTIONS * MAX_STREAMS_PER_CONNECTION;
if client.active_stream_count() + huge_stream_list.len() > capacity {
    client.unsubscribe(stale_streams).await?;
}
client.subscribe(huge_stream_list).await?;
Defensive patterns

Strategy: validation

Validate before calling

const POOL_CAPACITY: usize = MAX_CONNECTIONS * MAX_STREAMS_PER_CONNECTION;
if client.active_stream_count() + new_streams.len() > POOL_CAPACITY {
    // trim, shard, or unsubscribe first
}

Try / catch

match client.subscribe(streams).await {
    Err(e) if e.to_string().contains("pool exhausted") => {
        // degrade: reduce symbol set or fall back to REST polling
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling subscribe() with new streams when all pool slots already hold MAX_STREAMS_PER_CONNECTION streams and MAX_CONNECTIONS connections are open.

Common situations: Subscribing to very large instrument universes (hundreds/thousands of symbols) on Binance Spot, exceeding the 1024-streams-per-connection / limited-connections budget; forgetting to unsubscribe stale streams before adding new ones.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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