{"record":{"id":"0f55f7e48de30a0a","repo":"nautechsystems/nautilus_trader","slug":"no-healthy-transport-clients-available","errorCode":null,"errorMessage":"No healthy transport clients available","messagePattern":"No healthy transport clients available","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/bitmex/src/broadcast/canceller.rs","lineNumber":639,"sourceCode":"    /// Returns an error if all cancel requests fail or no healthy clients are available.\n    pub async fn broadcast_cancel(\n        &self,\n        instrument_id: InstrumentId,\n        client_order_id: Option<ClientOrderId>,\n        venue_order_id: Option<VenueOrderId>,\n    ) -> anyhow::Result<Option<OrderStatusReport>> {\n        self.total_cancels.fetch_add(1, Ordering::Relaxed);\n\n        let healthy_transports: Vec<TransportClient> = self\n            .transports\n            .iter()\n            .filter(|t| t.is_healthy())\n            .cloned()\n            .collect();\n\n        if healthy_transports.is_empty() {\n            self.failed_cancels.fetch_add(1, Ordering::Relaxed);\n            anyhow::bail!(\"No healthy transport clients available\");\n        }\n\n        let mut handles = Vec::new();\n\n        for transport in healthy_transports {\n            let handle = get_runtime().spawn(async move {\n                let client_id = transport.client_id.clone();\n                let result = transport\n                    .cancel_order(instrument_id, client_order_id, venue_order_id)\n                    .await\n                    .map(Some); // Wrap success in Some for Option<OrderStatusReport>\n                (client_id, result)\n            });\n            handles.push(handle);\n        }\n\n        self.process_cancel_results(\n            handles,","sourceCodeStart":621,"sourceCodeEnd":657,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bitmex/src/broadcast/canceller.rs#L621-L657","documentation":"broadcast_cancel collects the transport clients flagged healthy and aborts if none remain, incrementing the failed_cancels metric. This means every BitMEX transport connection is currently unhealthy (disconnected, reconnecting, or failed health checks), so there is no channel over which to send the cancel request.","triggerScenarios":"Calling broadcast_cancel(order_id) while all transports report is_healthy() == false — e.g. before the first connection is established, during an outage, or after all clients hit the failure threshold and were marked unhealthy.","commonSituations":"Network drop or BitMEX outage at the moment a strategy issues a cancel; startup ordering where cancels fire before transports connect; websocket auth failure marking all clients unhealthy; firewalled/restricted network blocking wss://www.bitmex.com.","solutions":["Check/restore network connectivity and wait for transport reconnect before retrying the cancel","Verify transports are connected and authenticated before submitting/cancelling orders (gate on a connected event)","Inspect health-check and reconnect logic/logs to see why all clients were marked unhealthy","Fall back to the REST cancel endpoint if available","If cancels can fire at startup, add a readiness check or startup delay"],"exampleFix":"// before\nlet result = canceller.broadcast_cancel(&cl_ord_id).await?;\n// after\nif !transport.is_healthy() {\n    transport.wait_until_healthy(timeout).await?; // or fallback to REST cancel\n}\nlet result = canceller.broadcast_cancel(&cl_ord_id).await;","handlingStrategy":"retry","validationCode":"// guard before cancelling\nif !transports.iter().any(|t| t.is_healthy()) {\n    return Err(NoHealthyTransport); // or wait/reconnect first\n}","typeGuard":"fn has_healthy_transport(transports: &[Transport]) -> bool {\n    transports.iter().any(|t| t.is_healthy())\n}","tryCatchPattern":"match canceller.broadcast_cancel(&cl_ord_id).await {\n    Err(e) if e.to_string().contains(\"No healthy transport clients\") => {\n        wait_for_reconnect(timeout).await?;\n        rest_client.cancel_order(&cl_ord_id).await?; // fallback\n    }\n    other => other?,\n}","preventionTips":["Gate order operations on a connected/ready signal","Implement REST fallback for cancels when websockets are down","Monitor transport health metrics and alert on total unhealth","Verify authentication succeeds at startup so clients become healthy"],"tags":["bitmex","websocket","availability","cancel"],"backgroundTag":"no-healthy-connections","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"}