nautechsystems/nautilus_trader · error · anyhow::Error

Failed to send subscribe command: {e}

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.

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)

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.