nautechsystems/nautilus_trader · error · anyhow::Error

Failed to send resubscribe command: {e}

Error message

Failed to send resubscribe command: {e}

What it means

This error wraps a failed send of HandlerCommand::Resubscribe on the internal mpsc command channel, used when re-establishing an existing subscription (e.g. after changing stream options). It fails only when the handler task's receiver is closed, meaning the handler loop is not running. Without the handler, the resubscribe request cannot reach the WebSocket connection.

Source

Thrown at crates/adapters/hyperliquid/src/websocket/client.rs:1864

        // Keep the registration check atomic with the resubscribe pair
        let cmd_tx = self.cmd_tx.write().await;

        if !self.quote_streams.contains_key(&coin) {
            log::debug!("Skipping bbo resubscribe for {coin}: stream no longer registered");
            return Ok(());
        }

        self.send_stream_resubscribe(&cmd_tx, SubscriptionRequest::Bbo { coin })
    }

    fn send_stream_resubscribe(
        &self,
        cmd_tx: &tokio::sync::mpsc::UnboundedSender<HandlerCommand>,
        subscription: SubscriptionRequest,
    ) -> anyhow::Result<()> {
        cmd_tx
            .send(HandlerCommand::Resubscribe { subscription })
            .map_err(|e| anyhow::anyhow!("Failed to send resubscribe command: {e}"))
    }

    /// Unsubscribe from trades for an instrument.
    pub async fn unsubscribe_trades(&self, instrument_id: InstrumentId) -> anyhow::Result<()> {
        self.unsubscribe_trade_stream(instrument_id, TradeStreamUse::Ticks)
            .await
    }

    /// Unsubscribe from complete public trades for an instrument.
    pub async fn unsubscribe_public_trades(
        &self,
        instrument_id: InstrumentId,
    ) -> anyhow::Result<()> {
        self.unsubscribe_trade_stream(instrument_id, TradeStreamUse::PublicTrades)
            .await
    }

    async fn unsubscribe_trade_stream(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Confirm the handler task is running before resubscribing; reconnect and resubscribe on a fresh client if it exited.
  2. Treat this during teardown as benign and skip the resubscribe.
  3. Serialize resubscribe calls with disconnect/shutdown to avoid races.
  4. Check handler logs for a panic that ended the loop.

Example fix

// before
client.disconnect().await?;
client.subscribe_book_depth10_with_options(id, Some(2), None).await?; // resubscribe path, channel closed

// after
client.connect().await?; // ensure handler is running
client.subscribe_book_depth10_with_options(id, Some(2), None).await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// rust
if !client.is_connected() {
    return Err(anyhow::anyhow!("cannot resubscribe: client disconnected"));
}

Try / catch

// rust
if let Err(e) = client.subscribe_book_depth10_with_options(id, Some(2), None).await {
    if e.to_string().contains("resubscribe") {
        client = reconnect_client().await?;
        client.subscribe_book_depth10_with_options(id, Some(2), None).await?;
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling a resubscribe-capable API (e.g. subscribe_book_depth10_with_options on an active stream with different options, routed through send_resubscribe) after disconnect() or handler-task exit.

Common situations: Re-subscribing after a reconnect attempt that left the handler dead; changing depth-10 options on a client whose handler already stopped; shutdown racing a resubscribe.

Related errors


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