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
- Reduce the number of simultaneously subscribed streams; unsubscribe instruments no longer needed before subscribing new ones.
- Split the workload across multiple pool/client instances (e.g., per asset class or shard).
- Check MAX_STREAMS_PER_CONNECTION/MAX_CONNECTIONS constants against current Binance limits and adjust configuration if they are outdated.
- 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
- Track active stream counts against MAX_CONNECTIONS * MAX_STREAMS_PER_CONNECTION before subscribing.
- Unsubscribe stale instruments before adding new ones.
- Shard large universes across multiple clients/instances.
- Keep adapter constants in sync with current Binance Spot limits.
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
- WS user data subscription timed out
- subscription confirmation failed: {e}
- invalid Derive subscription channel `{channel}`
- Failed to send UpdateInstrument command: {e}
- Lighter index price subscriptions require a perpetual or spo
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/08fa512031112616.
Report an issue: GitHub.