nautechsystems/nautilus_trader · error · anyhow::Error
Failed to send Subscribe command: {e}
Error message
Failed to send Subscribe command: {e} What it means
`subscribe` dispatches the subscription to the internal handler task over an mpsc command channel. If the send fails (the receiver/handler task has already terminated), the error is wrapped as 'Failed to send Subscribe command'. This indicates the client's background handler is no longer running.
Source
Thrown at crates/adapters/coinbase/src/websocket/client.rs:424
let channel_str = channel.as_ref();
if product_ids.is_empty() {
self.subscriptions.mark_subscribe(channel_str);
} else {
for product_id in product_ids {
let topic = format!("{channel_str}|{product_id}");
self.subscriptions.mark_subscribe(&topic);
}
}
let cmd_tx = self.cmd_tx.read().await;
cmd_tx
.send(HandlerCommand::Subscribe {
channel: sub.channel,
product_ids: sub.product_ids,
payload: sub.payload,
})
.map_err(|e| anyhow::anyhow!("Failed to send Subscribe command: {e}"))
}
/// Unsubscribes from a channel for the given product IDs.
pub async fn unsubscribe(
&self,
channel: CoinbaseWsChannel,
product_ids: &[Ustr],
) -> anyhow::Result<()> {
let jwt = self.credential.as_ref().and_then(|c| c.build_ws_jwt().ok());
let unsub = protect_subscription(CoinbaseWsSubscription {
msg_type: CoinbaseWsAction::Unsubscribe,
product_ids: product_ids.to_vec(),
channel,
jwt,
})?;
let channel_str = channel.as_ref();View on GitHub (pinned to 18893faf8b)
Solutions
- Check that the client/handler task is still running before subscribing; recreate the client if it was shut down
- Retry connect() to restart the task generation, then resubscribe
- Inspect logs for handler task panics or disconnects preceding the error
- Guard the shutdown path so subscribe is not called concurrently with close
Example fix
// before
client.subscribe(channel, &products).await?;
// after
if client.is_closed() {
client.reconnect().await?;
}
client.subscribe(channel, &products).await?; Defensive patterns
Strategy: try-catch
Validate before calling
async fn ensure_active(client: &CoinbaseWsClient) -> Result<(), anyhow::Error> {
if client.is_closed() {
anyhow::bail!("websocket client already closed; reconnect before subscribing");
}
Ok(())
} Try / catch
match client.subscribe(channel, &products).await {
Err(e) if e.to_string().contains("Failed to send Subscribe command") => {
client.reconnect().await?;
client.subscribe(channel, &products).await?;
}
other => other?,
} Prevention
- Keep a single owner of client lifecycle; never subscribe after close()
- Handle reconnects centrally so handler-task death always triggers recreation
- Watch for handler task panics in logs; they surface later as subscribe send failures
When it happens
Trigger: Calling `subscribe` after the websocket handler task exited (connection dropped permanently, client shut down, or the task panicked), so `cmd_tx.send(HandlerCommand::Subscribe)` returns a SendError.
Common situations: Reusing a client after `close`/drop of the handler, subscribe racing with shutdown during app teardown, or handler task crash on malformed state.
Related errors
- Failed to send Unsubscribe command: {e}
- Failed to send SetClient command: {e}
- WS handler command sender unavailable
- std::mem::take(&mut self.shutdown_errors).join("; ")
- Binance Spot public JSON stream pool is shutting down
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b665208caf4ee4d3.
Report an issue: GitHub.