nautechsystems/nautilus_trader · error
No healthy transport clients available
Error message
No healthy transport clients available
What it means
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.
Source
Thrown at crates/adapters/bitmex/src/broadcast/canceller.rs:639
/// Returns an error if all cancel requests fail or no healthy clients are available.
pub async fn broadcast_cancel(
&self,
instrument_id: InstrumentId,
client_order_id: Option<ClientOrderId>,
venue_order_id: Option<VenueOrderId>,
) -> anyhow::Result<Option<OrderStatusReport>> {
self.total_cancels.fetch_add(1, Ordering::Relaxed);
let healthy_transports: Vec<TransportClient> = self
.transports
.iter()
.filter(|t| t.is_healthy())
.cloned()
.collect();
if healthy_transports.is_empty() {
self.failed_cancels.fetch_add(1, Ordering::Relaxed);
anyhow::bail!("No healthy transport clients available");
}
let mut handles = Vec::new();
for transport in healthy_transports {
let handle = get_runtime().spawn(async move {
let client_id = transport.client_id.clone();
let result = transport
.cancel_order(instrument_id, client_order_id, venue_order_id)
.await
.map(Some); // Wrap success in Some for Option<OrderStatusReport>
(client_id, result)
});
handles.push(handle);
}
self.process_cancel_results(
handles,View on GitHub (pinned to 18893faf8b)
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
Example fix
// before
let result = canceller.broadcast_cancel(&cl_ord_id).await?;
// after
if !transport.is_healthy() {
transport.wait_until_healthy(timeout).await?; // or fallback to REST cancel
}
let result = canceller.broadcast_cancel(&cl_ord_id).await; Defensive patterns
Strategy: retry
Validate before calling
// guard before cancelling
if !transports.iter().any(|t| t.is_healthy()) {
return Err(NoHealthyTransport); // or wait/reconnect first
} Type guard
fn has_healthy_transport(transports: &[Transport]) -> bool {
transports.iter().any(|t| t.is_healthy())
} Try / catch
match canceller.broadcast_cancel(&cl_ord_id).await {
Err(e) if e.to_string().contains("No healthy transport clients") => {
wait_for_reconnect(timeout).await?;
rest_client.cancel_order(&cl_ord_id).await?; // fallback
}
other => other?,
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Both `api_key` and `api_secret` must be provided together
- No active WebSocket client
- Missing root_symbol for {}
- Missing underlying for {}
- Missing quote_currency for {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/0f55f7e48de30a0a.
Report an issue: GitHub.