nautechsystems/nautilus_trader · error · anyhow::Error
Failed to set Spot public JSON WS client: {e}
Error message
Failed to set Spot public JSON WS client: {e} What it means
After connecting, create_connection() sends BinanceSpotPublicWsCommand::SetClient(client) to the freshly spawned handler task so it holds the live WS client. This error means that send failed because the handler task/channel is already gone — the handler exited immediately after being spawned.
Source
Thrown at crates/adapters/binance/src/spot/websocket/public_json/client.rs:598
Some(shutdown_error) => format!(
"Failed to start Spot public JSON WS bytes task: {e}; startup rollback failed: \
{shutdown_error}"
),
None => format!("Failed to start Spot public JSON WS bytes task: {e}"),
});
}
let mut handler = BinanceSpotPublicWsHandler::new(
self.signal.clone(),
cmd_rx,
bytes_rx,
subscriptions_state.clone(),
self.request_id_counter.clone(),
);
cmd_tx
.send(BinanceSpotPublicWsCommand::SetClient(client))
.map_err(|e| anyhow::anyhow!("Failed to set Spot public JSON WS client: {e}"))?;
let signal = self.signal.clone();
let token = cancellation_token.clone();
let resubscribe_tx = cmd_tx.clone();
let mut handler_task = TaskSlot::new();
if let Err(e) = handler_task.spawn(async move {
loop {
tokio::select! {
() = token.cancelled() => {
log::debug!("Spot public JSON handler task cancelled");
break;
}
result = handler.next() => {
match result {
Some(BinanceSpotPublicWsMessage::Reconnected) => {
log::info!("Spot public JSON WebSocket reconnected, restoring subscriptions");
let topics = subscriptions_state.all_topics();View on GitHub (pinned to 18893faf8b)
Solutions
- Retry the connect — a fresh create_connection will spawn a new handler; transient races usually resolve.
- Check logs for handler task panics during startup and fix the panic root cause.
- Ensure the runtime/cancellation token is not cancelled while connections are being established; complete connects before shutdown.
- Verify the tokio runtime stays alive for the pool's lifetime (don't drop the runtime that spawned handler tasks).
Example fix
// before
let handle = tokio::spawn(handler_loop()); // runtime may be shutting down
handle.await?;
// after
if runtime_handle.runtime().is_none() || shutdown_flag.load(Ordering::SeqCst) {
return Err(anyhow!("cannot create connection during shutdown"));
}
let handle = runtime_handle.spawn(handler_loop());
handle.await?; Defensive patterns
Strategy: retry
Try / catch
match client.connect().await {
Err(e) if e.to_string().contains("Failed to set Spot public JSON WS client") => {
tokio::time::sleep(Duration::from_millis(500)).await;
client.connect().await?; // respawn handler and retry SetClient
}
r => r,
} Prevention
- Keep the tokio runtime alive for the pool's entire lifetime.
- Do not cancel the pool's cancellation token while connects are in flight.
- Check handler task startup code for panics.
- Sequence shutdown after all connection setup futures complete.
When it happens
Trigger: The handler task dies between spawn and the SetClient send — e.g. the cancellation token was already cancelled, the runtime is shutting down, or the handler task panicked on startup.
Common situations: Application/runtime shutdown racing connection setup; a bug or panic in the handler's initialization; spawning the task on a shutting-down tokio runtime; pool partially closed while subscribe()/connect() still runs.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- WS setup error channel closed
- Failed to send SetClient command: {e}
- Hyperliquid WebSocket handler failed: {error}
- Failed to send UpdateInstrument command: {e}
- Failed to send subscribe command: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/237ca93358dd9ade.
Report an issue: GitHub.