nautechsystems/nautilus_trader · warning · anyhow::Error

Failed to send pong: {e}

Error message

Failed to send pong: {e}

What it means

OKX sends text `ping` frames on its WebSocket; the handler responds with a pong via the sink. If the send fails (socket closed, backpressure, or send channel dropped), the handler logs a warning and returns this error, which typically triggers reconnect logic because the connection is no longer healthy.

Source

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

        rate_limit_keys: Option<&[Ustr]>,
    ) -> Result<(), OKXWsError> {
        let client = self.inner.as_ref().ok_or(OKXWsError::NoActiveClient)?;
        let connection_epoch = client.connection_epoch();
        client
            .send_text_on_connection(payload, rate_limit_keys, connection_epoch)
            .await
            .map_err(OKXWsError::TransportSend)
    }

    pub(super) async fn send_pong(&self) -> anyhow::Result<()> {
        match self.send_on_connection(TEXT_PONG.to_string(), None).await {
            Ok(()) => {
                log::trace!("Sent pong response to OKX text ping");
                Ok(())
            }
            Err(e) => {
                log::warn!("Failed to send pong: error={e}");
                Err(anyhow::anyhow!("Failed to send pong: {e}"))
            }
        }
    }

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

        let mut poll_raw_next = false;

        loop {
            if self.signal.load(Ordering::Acquire) {
                log::debug!("Stop signal received");
                return None;
            }

            tokio::select! {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Let the error propagate to the reconnect loop and re-establish the connection — the socket is already unusable.
  2. Check network/proxy idle timeouts and enable keep-alive so pings can be answered in time.
  3. Verify the write half of the WebSocket is still shared/alive when the handler runs.
Defensive patterns

Strategy: try-catch

Try / catch

// treat as connection-lost: trigger reconnect
if let Err(e) = handler_result {
    log::warn!("ws unhealthy: {e}; reconnecting");
    reconnect_with_backoff().await;
}

Prevention

When it happens

Trigger: OKX sends a text ping while the underlying WebSocket is closed/broken or the send sink is unavailable, so `send(...)` returns Err in `send_pong`.

Common situations: Network interruption mid-session; server closed the connection while a queued ping was being answered; proxy or firewall idle-timeout dropped the socket.

Related errors


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