nautechsystems/nautilus_trader · error · anyhow::Error
Failed to send SetDepth10Sub command: {e}
Error message
Failed to send SetDepth10Sub command: {e} What it means
This error wraps a failed send of the SetDepth10Sub(subscribed: true) command on the client's internal mpsc command channel. It is thrown right after the UpdateInstrument registration during depth-10 subscription, so the handler task stopped accepting commands between the two sends. It indicates the WebSocket handler receiver is closed.
Source
Thrown at crates/adapters/hyperliquid/src/websocket/client.rs:1405
mantissa: Option<u32>,
) -> anyhow::Result<()> {
let instrument = self
.get_instrument(&instrument_id)
.ok_or_else(|| InstrumentLookupError::not_found(instrument_id))?;
let coin = instrument.raw_symbol().inner();
let cmd_tx = self.cmd_tx.read().await;
cmd_tx
.send(HandlerCommand::UpdateInstrument(instrument.clone()))
.map_err(|e| anyhow::anyhow!("Failed to send UpdateInstrument command: {e}"))?;
cmd_tx
.send(HandlerCommand::SetDepth10Sub {
coin,
subscribed: true,
})
.map_err(|e| anyhow::anyhow!("Failed to send SetDepth10Sub command: {e}"))?;
self.send_book_stream_subscribe(&cmd_tx, coin, BookStreamUse::Depth10, n_sig_figs, mantissa)
}
/// Unsubscribe from order book depth-10 snapshots.
///
/// Clears the depth10 emission flag and tears down the underlying
/// `l2Book` stream unless active deltas subscribers still need it.
pub async fn unsubscribe_book_depth10(
&self,
instrument_id: InstrumentId,
) -> anyhow::Result<()> {
let instrument = self
.get_instrument(&instrument_id)
.ok_or_else(|| InstrumentLookupError::not_found(instrument_id))?;
let coin = instrument.raw_symbol().inner();
let cmd_tx = self.cmd_tx.read().await;View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the handler task is alive (JoinHandle not finished) before subscribing; respawn/reconnect if it exited.
- Avoid calling subscribe concurrently with disconnect/shutdown; sequence them or guard with application-level state.
- Re-create the client if the handler loop exited; the channel cannot be revived.
- Check handler-task logs/panic hooks for the root cause of the loop exiting.
Example fix
// before
client.disconnect().await?;
client.subscribe_book_depth10(instrument_id).await?; // channel already closed
// after
if !client.is_connected() {
client.connect().await?;
}
client.subscribe_book_depth10(instrument_id).await?; Defensive patterns
Strategy: try-catch
Validate before calling
// rust
if !client.is_connected() {
return Err(anyhow::anyhow!("client not connected before depth10 subscribe"));
} Try / catch
// rust
if let Err(e) = client.subscribe_book_depth10(instrument_id).await {
if e.to_string().contains("SetDepth10Sub") {
tracing::warn!("handler channel closed ({e}); re-establishing client");
client = reconnect_client().await?;
client.subscribe_book_depth10(instrument_id).await?;
} else { return Err(e); }
} Prevention
- Keep the handler task running until all subscriptions are torn down.
- Avoid racing subscribe with disconnect/shutdown; use a connection-state guard.
- Log handler task completion (JoinHandle await) to detect premature exit.
- Re-create the client after any handler-channel failure; never reuse it.
When it happens
Trigger: Calling subscribe_book_depth10 when the handler task has already terminated — after disconnect(), after the handler task panicked or its JoinHandle/receiver was dropped, or on a client whose run loop exited between the preceding UpdateInstrument send and this one.
Common situations: Subscribe racing with shutdown/disconnect; handler task crashed earlier (check its logs); client used after being moved into a scope that ended; runtime shutdown during teardown.
Related errors
- Failed to send UpdateTradeSubs command: {e}
- Failed to send AddBarType command: {e}
- Failed to send resubscribe command: {e}
- Failed to send RemoveBarType command: {e}
- Failed to send subscribe command: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/caaac1aecf947fd0.
Report an issue: GitHub.