{"record":{"id":"94448f177835abe5","repo":"nautechsystems/nautilus_trader","slug":"rtds-websocket-client-unavailable-after-reconcile","errorCode":null,"errorMessage":"RTDS WebSocket client unavailable after reconcile","messagePattern":"RTDS WebSocket client unavailable after reconcile","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/rtds.rs","lineNumber":833,"sourceCode":"                }\n            }\n        }\n    }\n\n    async fn reconcile_once(&self, reset_live_state: bool) -> anyhow::Result<()> {\n        let _guard = self.inner.wire_mutex.lock().await;\n\n        if self.inner.closing.load(Ordering::Acquire) {\n            return Ok(());\n        }\n\n        if !self.has_subscriptions() && self.current_ws().is_none() {\n            return Ok(());\n        }\n\n        let fresh_connect = self.ensure_connected_locked().await?;\n        let Some(ws) = self.current_ws() else {\n            anyhow::bail!(\"RTDS WebSocket client unavailable after reconcile\");\n        };\n\n        self.reconcile_live_locked(&ws, fresh_connect || reset_live_state)\n            .await\n    }\n\n    async fn ensure_connected_locked(&self) -> anyhow::Result<bool> {\n        let generation = {\n            let generation = self.inner.shutdown_generation.lock();\n\n            if self.inner.closing.load(Ordering::Acquire) {\n                return Ok(false);\n            }\n            *generation\n        };\n\n        if self.current_ws().is_some_and(|ws| !ws.is_disconnected()) {\n            return Ok(false);","sourceCodeStart":815,"sourceCodeEnd":851,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/rtds.rs#L815-L851","documentation":"Raised after a reconcile attempts to (re)establish the RTDS WebSocket: ensure_connected_locked returned success but current_ws() still yields no client. This is an internal invariant violation — the code expected ensure_connected_locked to install a WebSocket client whenever subscriptions exist.","triggerScenarios":"ensure_connected_locked returns Ok without installing a client while has_subscriptions() is true and no WebSocket client is stored — e.g. a swallowed shutdown bail in the connect path, or a race where the installed client was cleared between connect and lookup.","commonSituations":"Concurrent shutdown clearing ws_client while reconcile runs; subscriptions added just as the feed is being torn down; a modified connect path that returns Ok without storing the client.","solutions":["Ensure ensure_connected_locked always either installs a client or returns an error; propagate shutdown bails instead of swallowing them.","Hold the state lock across connect and the ws lookup so shutdown cannot clear the client in between.","Re-check the shutdown/generation state after ensure_connected_locked and return a cancellation error instead.","If it persists, file a bug: this indicates a real invariant break in the feed's connect logic."],"exampleFix":"// before\nlet fresh_connect = self.ensure_connected_locked().await?;\nlet Some(ws) = self.current_ws() else {\n    anyhow::bail!(\"RTDS WebSocket client unavailable after reconcile\");\n};\n// after\nlet fresh_connect = self.ensure_connected_locked().await?;\nif !self.is_generation_open(generation) {\n    anyhow::bail!(\"RTDS reconcile was canceled by shutdown\");\n}\nlet Some(ws) = self.current_ws() else {\n    anyhow::bail!(\"RTDS WebSocket client unavailable after reconcile\");\n};","handlingStrategy":"retry","validationCode":"// before reconcile\nif !feed.has_subscriptions() && !feed.has_ws_client() {\n    return Ok(());\n}\nif feed.is_shutdown() {\n    return Ok(());\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = feed.reconcile().await {\n    if e.to_string().contains(\"unavailable after reconcile\") {\n        log::error!(\"RTDS reconcile invariant violated: {e:#}\");\n        // recreate the feed instance\n    }\n    return Err(e);\n}","preventionTips":["Do not swallow errors from connect/reconnect helpers — propagate them so invariants stay intact.","Serialize lifecycle operations; avoid concurrent reconcile/shutdown calls.","Recreate the feed instance if this error appears; internal state is inconsistent.","Report persistent occurrences as a bug with logs around the connect path."],"tags":["websocket","invariant","reconcile","polymarket","internal-error"],"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"}