{"record":{"id":"f8f10cfe52f3c09f","repo":"nautechsystems/nautilus_trader","slug":"no-active-websocket-client","errorCode":null,"errorMessage":"No active WebSocket client","messagePattern":"No active WebSocket client","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/spot/websocket/streams/handler.rs","lineNumber":292,"sourceCode":"                payload,\n                Some(BINANCE_RATE_LIMIT_KEY_SUBSCRIPTION.as_slice()),\n            )\n            .await\n        {\n            self.pending_requests.take(request_id);\n            return Err(e);\n        }\n\n        Ok(())\n    }\n\n    async fn send_text(\n        &self,\n        payload: String,\n        rate_limit_keys: Option<&[Ustr]>,\n    ) -> anyhow::Result<()> {\n        let Some(client) = &self.inner else {\n            anyhow::bail!(\"No active WebSocket client\");\n        };\n        client\n            .send_text(payload, rate_limit_keys)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to send message: {e}\"))?;\n        Ok(())\n    }\n}\n\n/// Classifies a JSON text frame that did not match a subscription response or\n/// known error envelope. Recognizes the `serverShutdown` event; otherwise\n/// emits `RawJson` for parseable payloads or an empty vector for garbage.\nfn classify_unsolicited_json(text: &str) -> Vec<BinanceSpotWsMessage> {\n    let Ok(value) = serde_json::from_str::<serde_json::Value>(text) else {\n        log::warn!(\"Failed to parse JSON message: {text}\");\n        return vec![];\n    };\n","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/binance/src/spot/websocket/streams/handler.rs#L274-L310","documentation":"The streams WebSocket handler's send_text requires an active inner WS client; when self.inner is None the handler has no established connection to send on, so it bails. Messages can only be sent after a successful connect that populates inner.","triggerScenarios":"handle_subscribe or handle_unsubscribe calling send_text before connect() completed, or after the inner client was cleared by disconnect/reconnect, or when a connection was never established because connect failed.","commonSituations":"Subscribing immediately after constructing the handler without connecting; a dropped connection cleared inner while subscription management still runs; reconnection windows where commands arrive between disconnect and reconnect.","solutions":["Ensure connect() is awaited and succeeded before any subscribe/unsubscribe commands.","Buffer or re-queue subscription commands during reconnection and replay once the client is active.","Check logs for the disconnect that cleared inner; if unexpected, investigate connection stability.","Guard the caller with a connected-state check before sending commands."],"exampleFix":"// before\nhandler.send_text(payload, keys).await?;\n// after\nif !handler.is_connected().await {\n    log::warn!(\"not connected, queuing subscribe command\");\n    pending_commands.push((payload, keys));\n} else {\n    handler.send_text(payload, keys).await?;\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"async fn is_connected(handler: &Handler) -> bool { handler.inner.is_some() }","tryCatchPattern":"match handler.send_text(payload, keys).await {\n    Err(e) if e.to_string().contains(\"No active WebSocket client\") => {\n        queue_for_replay((payload, keys)); // resend after reconnect\n    }\n    other => other?,\n}","preventionTips":["Always await connect() successfully before issuing subscribe/unsubscribe commands.","Queue commands during reconnection windows and replay them once the client is active.","Track connection state in the caller and gate all sends on it.","Investigate unexpected disconnects that clear the inner client."],"tags":["websocket","binance","spot","not-connected","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}