{"record":{"id":"c55a922e0ed41cee","repo":"nautechsystems/nautilus_trader","slug":"ws-message-receiver-not-available-after-connect","errorCode":null,"errorMessage":"WS message receiver not available after connect","messagePattern":"WS message receiver not available after connect","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/data/lifecycle.rs","lineNumber":541,"sourceCode":"        log::info!(\"Connecting Polymarket data client\");\n\n        log::debug!(\"Bootstrapping instruments from Gamma API...\");\n        self.bootstrap_instruments().await?;\n        log::debug!(\n            \"Bootstrap complete, {} instruments loaded\",\n            self.instruments.load().len(),\n        );\n\n        self.ws_client.connect().await?;\n\n        let session_result = async {\n            if self.config.subscribe_new_markets {\n                log::debug!(\"Subscribing to new markets...\");\n                self.ws_client.subscribe_new_markets_feed().await?;\n            }\n\n            let rx = self.ws_client.take_message_receiver().ok_or_else(|| {\n                anyhow::anyhow!(\"WS message receiver not available after connect\")\n            })?;\n\n            self.register_message_handler(rx)?;\n            self.register_instrument_refresh_task()?;\n            self.register_resolve_poll_task()?;\n\n            // Connect unconditionally: this clears the feed's closing latch from a prior\n            // disconnect; without retained subscriptions no RTDS socket is opened.\n            self.rtds_feed.connect().await\n        }\n        .await;\n\n        if let Err(e) = session_result {\n            if let Err(teardown_error) = self.disconnect_client().await {\n                log::warn!(\n                    \"Error tearing down partial Polymarket data connection: {teardown_error:?}\"\n                );\n            }","sourceCodeStart":523,"sourceCodeEnd":559,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/data/lifecycle.rs#L523-L559","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Do not share or reuse ws_client handles across connect cycles; create a fresh client per connection","Avoid concurrent connect() calls on the same client","Rebuild the client if a previous connect consumed the receiver without completing","Check the WS client construction path to ensure the message channel is always installed"],"exampleFix":"// before\nlet rx1 = ws.take_message_receiver(); // first connect\nlet rx2 = ws.take_message_receiver(); // None -> error\n// after\nlet client = PolymarketDataClient::new(...)?; // fresh client per connect\nclient.connect().await?;","handlingStrategy":"validation","validationCode":"// before connect, ensure this is a fresh client and no other connect is in flight\nassert!(!connect_in_progress.load(Ordering::SeqCst));","typeGuard":"fn receiver_expected(ws: &PolymarketWsClient) -> bool { !ws.receiver_taken() }","tryCatchPattern":"if let Err(e) = client.connect().await {\n    if e.to_string().contains(\"receiver not available\") {\n        // receiver already consumed: must rebuild client\n        client = build_client(cfg)?;\n        client.connect().await?;\n    }\n}","preventionTips":["Never reuse a client/ws handle whose connect already consumed the message receiver","Protect connect() with a mutex or atomic so it cannot run twice concurrently","Construct a new data client for each connection cycle"],"tags":["rust","websocket","invariant","polymarket"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}