nautechsystems/nautilus_trader · error · anyhow::Error

No WebSocket client available

Error message

No WebSocket client available

What it means

send_with_retry returns this error when the handler has no WebSocket client instance to send through — the Option holding the client is None. This happens before a connection is established or after the client was taken/cleared during teardown.

Source

Thrown at crates/adapters/hyperliquid/src/websocket/handler.rs:352

                    || {
                        let payload = payload.clone();
                        async move {
                            client
                                .send_text(payload, Some(std::slice::from_ref(&rate_key)))
                                .await
                                .map_err(|e| {
                                    HyperliquidWsError::ClientError(format!("Send failed: {e}"))
                                })
                        }
                    },
                    should_retry_hyperliquid_error,
                    |e| create_hyperliquid_timeout_error(e.to_string()),
                )
                .execute()
                .await
                .map_err(|e| anyhow::anyhow!("{e}"))
        } else {
            Err(anyhow::anyhow!("No WebSocket client available"))
        }
    }

    pub(super) async fn next(&mut self) -> Option<NautilusWsMessage> {
        if let Some(msg) = self.message_buffer.pop_front() {
            return Some(msg);
        }

        loop {
            if self.raw_closed && self.cmd_rx.is_empty() {
                log::debug!("Handler shutting down: input stream closed");
                return None;
            }

            tokio::select! {
                cmd = self.cmd_rx.recv(), if !self.cmd_closed => {
                    let Some(cmd) = cmd else {
                        self.cmd_closed = true;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure connect() has succeeded before issuing commands
  2. Wait for connection-established signal before replaying subscriptions
  3. During reconnect, buffer commands and replay only after the new client is attached
  4. Treat the error as a lifecycle bug and re-initialize the handler/client pair

Example fix

// before
handler.handle_command(cmd).await?;
// after
assert!(handler.is_connected(), "handler has no ws client");
handler.handle_command(cmd).await?;
Defensive patterns

Strategy: type-guard

Validate before calling

// Rust
fn handler_ready(handler: &HyperliquidWsHandler) -> bool {
    handler.has_client()
}

Type guard

// check before sending commands
if !handler.has_client() {
    return Err(anyhow::anyhow!("handler not connected yet"));
}

Try / catch

if let Err(e) = handler.handle_command(cmd).await {
    if e.to_string().contains("No WebSocket client") {
        wait_until_connected().await?;
        handler.handle_command(cmd).await?;
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: handle_command or replay_subscriptions is called on a handler that has not been given a WebSocket client (pre-connect) or after disconnect/cleanup cleared it. There is no retry possible; it fails fast.

Common situations: Calling subscribe/replay before connect() completes; using the handler after close(); a reconnect cycle where the client was dropped but commands still arrive in the queue.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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