nautechsystems/nautilus_trader · error · anyhow::Error
Failed to send UpdateInstrument command: {e}
Error message
Failed to send UpdateInstrument command: {e} What it means
Raised when updating the handler's coin-to-instrument mapping via HandlerCommand::UpdateInstrument during a quote/BBO subscription: the mpsc send fails because the handler task's command receiver is gone, meaning the handler task has stopped. The method rolls back the just-inserted quote_streams entry and propagates the error, leaving the client without the subscription.
Source
Thrown at crates/adapters/hyperliquid/src/websocket/client.rs:1448
.map_err(|e| anyhow::anyhow!("Failed to send SetDepth10Sub command: {e}"))?;
self.send_book_stream_unsubscribe(&cmd_tx, coin, BookStreamUse::Depth10)
}
/// Subscribe to best bid/offer (BBO) quotes for an instrument.
pub async fn subscribe_quotes(&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;
self.quote_streams.insert(coin, ());
// Update the handler's coin→instrument mapping for this subscription
if let Err(e) = cmd_tx.send(HandlerCommand::UpdateInstrument(instrument.clone())) {
self.quote_streams.remove(&coin);
anyhow::bail!("Failed to send UpdateInstrument command: {e}");
}
let subscription = SubscriptionRequest::Bbo { coin };
if let Err(e) = self.send_subscription(&cmd_tx, subscription) {
self.quote_streams.remove(&coin);
return Err(e);
}
Ok(())
}
/// Subscribe to all mid prices across markets.
pub async fn subscribe_all_mids(&self) -> anyhow::Result<()> {
self.subscribe_all_mids_with_dex(None).await
}
/// Subscribe to aggregate asset contexts across all perp dexes.
pub async fn subscribe_all_dexs_asset_ctxs(&self) -> anyhow::Result<()> {View on GitHub (pinned to 18893faf8b)
Solutions
- Check connection state before subscribing and reconnect (or recreate the client) if the handler is down, then retry the subscription.
- Look for a preceding handler panic/exit in logs and fix that root cause.
- Avoid racing disconnect() with subscribe(); sequence them or check a connection flag first.
- Surface this error to the caller rather than ignoring it, since quote streams will not flow.
Example fix
// before: subscribe on dead handler task / client.subscribe_quote_streams(coin, instrument).await?; / // after: re-establish handler first / if !client.is_connected() { client.connect().await?; } / client.subscribe_quote_streams(coin, instrument).await?; Defensive patterns
Strategy: validation
Validate before calling
fn can_subscribe(cmd_tx: &tokio::sync::mpsc::Sender<HandlerCommand>) -> bool { !cmd_tx.is_closed() } Type guard
fn is_subscribable(client: &HyperliquidWebSocketClient) -> bool { client.is_connected() } Try / catch
match client.subscribe_quote_streams(coin, instrument).await { Err(e) if e.to_string().contains("UpdateInstrument command") => { client.connect().await?; client.subscribe_quote_streams(coin, instrument).await?; } Err(e) => return Err(e.into()), Ok(()) => {} } Prevention
- Check connection state before every subscription call.
- Reconnect promptly after disconnect/errors instead of reusing the dead client.
- Avoid racing disconnect() against subscribe() in concurrent code.
- Alert on this error; the subscription silently will not deliver quotes if ignored.
When it happens
Trigger: Calling the quote-stream subscription method when the handler task has exited (receiver dropped): after a disconnect, after a handler crash, or on a client whose handler already shut down.
Common situations: Subscribing on a disconnected or never-connected client; a handler panic killed the task mid-session; concurrent disconnect() racing subscribe(); stale client reused after a network failure terminated the handler.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- Failed to send SetClient command: {e}
- Handler not available for Spot JSON pool slot {slot_idx}: {e
- WS user data subscription timed out
- WS setup error channel closed
- subscription confirmation failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e0a1f85861725c4c.
Report an issue: GitHub.