nautechsystems/nautilus_trader · error · anyhow::Error

Failed to send subscribe command

Error message

Failed to send subscribe command: {e}

What it means

This error is raised when the WebSocket client fails to enqueue a Subscribe command onto the channel consumed by the connection's message-handler task (cmd_tx.send returns an error, which in Rust means the receiving task has been dropped, i.e. the handler/connection is shut down). The subscription is then aborted; if a rate-limit slot was reserved for the subscription it is released back before failing. It is a wrapping of an internal send failure, so the root cause is that the handler task is no longer running.

Solutions

  1. Check connection state before subscribing and reconnect the WebSocket client first; then retry the subscription.
  2. Wrap the subscribe call so the error is handled and the client is reconnected (call connect/reconnect), then re-issue the subscription.
  3. Avoid subscribing concurrently with shutdown: ensure the handler task is alive (guard with a ConnectionClosed/disconnected check or hold the client alive).
  4. Enable tracing logs to find why the handler task exited (network error, server close) and fix that root cause.

Example fix

// before
client.subscribe(subscription).await?;
// after
if client.is_connected() {
    if let Err(e) = client.subscribe(subscription).await {
        tracing::warn!("subscribe failed ({e}); reconnecting");
        client.connect().await?;
        client.subscribe(subscription).await?;
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before subscribing
if !ws_client.is_connected() {
    ws_client.connect().await?;
}

Type guard

fn can_subscribe(client: &HyperliquidWsClient) -> bool {
    client.is_connected()
}

Try / catch

match client.subscribe(subscription).await {
    Ok(()) => {}
    Err(e) if e.to_string().contains("Failed to send subscribe command") => {
        // handler task gone: reconnect then re-subscribe
        client.connect().await?;
        client.subscribe(subscription).await?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling a subscribe method (e.g. to subscribe to trades/l2Book/candle channels) when the underlying WebSocket handler task has already terminated or is being shut down. Any API path that builds a subscription and sends HandlerCommand::Subscribe through cmd_tx will produce this if the receiver was dropped.

Common situations: Subscribing after the connection dropped or was closed; racing a subscribe call with client shutdown/disconnect; a crashed or aborted handler task (network loss, server closed the socket, panic in handler) leaving the channel with no receiver; calling subscribe on a stale/cloned client handle after reconnect logic replaced the transport.

Related errors


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

Appendix: source

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

    fn send_subscription(
        &self,
        cmd_tx: &tokio::sync::mpsc::UnboundedSender<HandlerCommand>,
        subscription: SubscriptionRequest,
    ) -> anyhow::Result<()> {
        let key = crate::websocket::handler::subscription_to_key(&subscription);
        let reserved = self
            .rate_limits
            .reserve_subscription(self.client_id, &subscription)
            .map_err(anyhow::Error::msg)?;

        if let Err(e) = cmd_tx.send(HandlerCommand::Subscribe {
            subscriptions: vec![subscription],
        }) {
            if reserved {
                self.rate_limits.release_subscription(self.client_id, &key);
            }
            anyhow::bail!("Failed to send subscribe command: {e}");
        }
        Ok(())
    }

    fn send_unsubscription(
        &self,
        cmd_tx: &tokio::sync::mpsc::UnboundedSender<HandlerCommand>,
        subscription: SubscriptionRequest,
    ) -> anyhow::Result<()> {
        cmd_tx
            .send(HandlerCommand::Unsubscribe {
                subscriptions: vec![subscription],
            })
            .map_err(|e| anyhow::anyhow!("Failed to send unsubscribe command: {e}"))
    }

    /// Receives the next message from the WebSocket handler.
    ///

View on GitHub (pinned to 18893faf8b)