nautechsystems/nautilus_trader · error · anyhow::Error

Failed to send unsubscribe command: {e}

Error message

Failed to send unsubscribe command: {e}

What it means

This error is returned by send_unsubscription when the Unsubscribe HandlerCommand cannot be sent to the handler task over the command channel. The channel being closed means the handler task that processes unsubscriptions has terminated.

Source

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

        }) {
            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.
    ///
    /// Returns `None` if the handler has disconnected or the receiver was already taken.
    pub async fn next_event(&mut self) -> Option<NautilusWsMessage> {
        if let Some(ref mut rx) = self.out_rx {
            rx.recv().await
        } else {
            None
        }
    }

    fn release_limit_reservations(&self) {
        self.rate_limits.release_client(self.client_id);
        self.connection_permit.lock().take();
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Guard unsubscribe calls with a connection-alive check
  2. If disconnected, drop local state instead of sending the command
  3. Reconnect/recreate the client before further use
  4. Check logs for a prior handler task panic

Example fix

// before
client.unsubscribe(data_type).await?;
// after
if client.is_connected() {
    client.unsubscribe(data_type).await?;
} else {
    log::warn!("skipping unsubscribe, handler disconnected");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust
fn should_unsubscribe(client: &HyperliquidWsClient) -> bool {
    client.is_connected()
}

Try / catch

if client.is_connected() {
    client.unsubscribe(sub).await?;
} else {
    log::debug!("handler disconnected; skipping unsubscribe");
}

Prevention

When it happens

Trigger: Any call to unsubscribe(...) after the handler task has dropped its receiver — e.g. after a disconnect, handler panic, or client close while an unsubscribe is still pending.

Common situations: Application shutdown where cleanup calls unsubscribe after the connection already closed; a crashed handler task; using a client handle from a previous connection session.

Related errors


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