nautechsystems/nautilus_trader · error · anyhow::Error

WS message receiver not available after connect

Error message

WS message receiver not available after connect

What it means

After the WebSocket handshake and optional new-markets subscription, connect_client calls ws_client.take_message_receiver() which hands over the mpsc receiver exactly once. If it returns None, the WS client did not produce/hold a message receiver after connecting — an internal invariant breach — so connect fails.

Source

Thrown at crates/adapters/polymarket/src/data/lifecycle.rs:541

        log::info!("Connecting Polymarket data client");

        log::debug!("Bootstrapping instruments from Gamma API...");
        self.bootstrap_instruments().await?;
        log::debug!(
            "Bootstrap complete, {} instruments loaded",
            self.instruments.load().len(),
        );

        self.ws_client.connect().await?;

        let session_result = async {
            if self.config.subscribe_new_markets {
                log::debug!("Subscribing to new markets...");
                self.ws_client.subscribe_new_markets_feed().await?;
            }

            let rx = self.ws_client.take_message_receiver().ok_or_else(|| {
                anyhow::anyhow!("WS message receiver not available after connect")
            })?;

            self.register_message_handler(rx)?;
            self.register_instrument_refresh_task()?;
            self.register_resolve_poll_task()?;

            // Connect unconditionally: this clears the feed's closing latch from a prior
            // disconnect; without retained subscriptions no RTDS socket is opened.
            self.rtds_feed.connect().await
        }
        .await;

        if let Err(e) = session_result {
            if let Err(teardown_error) = self.disconnect_client().await {
                log::warn!(
                    "Error tearing down partial Polymarket data connection: {teardown_error:?}"
                );
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Do not share or reuse ws_client handles across connect cycles; create a fresh client per connection
  2. Avoid concurrent connect() calls on the same client
  3. Rebuild the client if a previous connect consumed the receiver without completing
  4. Check the WS client construction path to ensure the message channel is always installed

Example fix

// before
let rx1 = ws.take_message_receiver(); // first connect
let rx2 = ws.take_message_receiver(); // None -> error
// after
let client = PolymarketDataClient::new(...)?; // fresh client per connect
client.connect().await?;
Defensive patterns

Strategy: validation

Validate before calling

// before connect, ensure this is a fresh client and no other connect is in flight
assert!(!connect_in_progress.load(Ordering::SeqCst));

Type guard

fn receiver_expected(ws: &PolymarketWsClient) -> bool { !ws.receiver_taken() }

Try / catch

if let Err(e) = client.connect().await {
    if e.to_string().contains("receiver not available") {
        // receiver already consumed: must rebuild client
        client = build_client(cfg)?;
        client.connect().await?;
    }
}

Prevention

When it happens

Trigger: take_message_receiver() returns None after a successful WS connect: receiver already taken (double connect on the same ws_client handle), or the underlying WS client was reused/replaced and never set a new receiver.

Common situations: Reusing a data client (or manually its ws_client) across connect attempts without reconstruction; calling connect twice concurrently so one connect consumes the receiver; constructing the client against a ws_client that failed to initialize its channel.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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