nautechsystems/nautilus_trader · error · anyhow::Error

Handler not available for Spot JSON pool slot {slot_idx}: {e

Error message

Handler not available for Spot JSON pool slot {slot_idx}: {e}

What it means

subscribe() sends a Subscribe command to the handler task of the selected slot via its cmd_tx channel. This error means that send failed because the slot's handler task is no longer running (channel closed), even though the slot entry still exists in the pool.

Source

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

                })?;

            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(),
                })
                .map_err(|e| {
                    anyhow::anyhow!("Handler not available for Spot JSON pool slot {slot_idx}: {e}")
                })?;
            slots[*slot_idx].streams.extend(batch.iter().cloned());
        }

        Ok(())
    }

    /// Unsubscribes from stream names.
    ///
    /// # Errors
    ///
    /// Returns an error if command delivery fails.
    pub async fn unsubscribe(&self, streams: Vec<String>) -> anyhow::Result<()> {
        if streams.is_empty() {
            return Ok(());
        }

        let _connect_guard = self.connect_lock.lock().await;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry subscribe() so the pool can reconnect the dead slot via create_connection before dispatching.
  2. Check application logs for the handler task's exit reason (WS error, panic) and fix the root disconnect cause.
  3. Ensure shutdown is not concurrently tearing down handlers while subscribe() runs.
  4. If persistent, recreate the client/pool to rebuild all slots from scratch.

Example fix

// before
client.subscribe(streams).await?; // Err: Handler not available for slot 2

// after
match client.subscribe(streams).await {
    Err(e) if e.to_string().contains("Handler not available") => {
        tokio::time::sleep(Duration::from_secs(1)).await;
        client.subscribe(streams).await?; // reconnects dead slot
    }
    r => r?,
}
Defensive patterns

Strategy: retry

Try / catch

match client.subscribe(streams).await {
    Err(e) if e.to_string().contains("Handler not available") => {
        tokio::time::sleep(Duration::from_secs(1)).await;
        client.subscribe(streams).await?; // pool reconnects dead slot
    }
    r => r?,
}

Prevention

When it happens

Trigger: A slot's WebSocket handler task has exited (connection dropped terminally, task panicked, or pool partially shut down) and then subscribe() tries to route new streams to that dead slot.

Common situations: Network loss or Binance disconnect that permanently killed one handler while the pool bookkeeping still lists the slot; shutdown racing subscribe; a reconnect bug leaving a slot without a live handler.

Related errors


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