nautechsystems/nautilus_trader · warning · anyhow::Error

Failed to send unsubscription after retries: {e}

Error message

Failed to send unsubscription after retries: {e}

What it means

In `handle_unsubscribe`, the serialized unsubscribe message is sent via `send_with_retry` under the OKX subscription rate-limit key. If every retry fails (socket closed or rate limited), the error is wrapped with this message and the channel remains subscribed server-side until disconnect.

Source

Thrown at crates/adapters/okx/src/websocket/handler.rs:565

        for arg in &args {
            log::debug!(
                "Unsubscribing from channel: channel={:?}, inst_id={:?}",
                arg.channel,
                arg.inst_id
            );
        }

        let message = OKXSubscription {
            op: OKXWsOperation::Unsubscribe,
            args,
        };

        let json_txt = serde_json::to_string(&message)
            .map_err(|e| anyhow::anyhow!("Failed to serialize unsubscription: {e}"))?;

        self.send_with_retry(json_txt, Some(OKX_RATE_LIMIT_KEY_SUBSCRIPTION.as_slice()))
            .await
            .map_err(|e| anyhow::anyhow!("Failed to send unsubscription after retries: {e}"))?;
        Ok(())
    }

    pub(crate) fn parse_raw_message(
        msg: tokio_tungstenite::tungstenite::Message,
    ) -> Option<OKXWsFrame> {
        match msg {
            tokio_tungstenite::tungstenite::Message::Text(text) => {
                if text == TEXT_PONG {
                    log::trace!("Received pong from OKX");
                    return None;
                }

                if text == TEXT_PING {
                    log::trace!("Received ping from OKX (text)");
                    return Some(OKXWsFrame::Ping);
                }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Treat as non-fatal during shutdown: the server drops all subscriptions when the socket closes anyway.
  2. If you need the channel truly unsubscribed, reconnect and either resubscribe with the correct set or skip the stale channel.
  3. Check the inner `{e}` to confirm it is a transport error rather than rate limiting.
Defensive patterns

Strategy: try-catch

Try / catch

// rust
// during teardown, unsubscribe failure is benign: server drops state on close
if let Err(e) = unsubscribe(arg).await {
    log::debug!("unsubscribe failed (ignored during shutdown): {e}");
}

Prevention

When it happens

Trigger: Unsubscribing while the WebSocket connection is down, or sends keep failing across the retry window due to OKX rate limits.

Common situations: Unsubscribing during a network drop or after the server already closed the socket; tearing down many subscriptions at once during shutdown.

Related errors


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