nautechsystems/nautilus_trader · error · anyhow::Error
Failed to send UnsubscribeMarket: {e}
Error message
Failed to send UnsubscribeMarket: {e} What it means
unsubscribe_market() enqueues HandlerCommand::UnsubscribeMarket on the internal mpsc channel to the feed-handler task. It fails only when the receiver has been dropped because the handler task has exited, meaning there is no active session to process the unsubscribe.
Source
Thrown at crates/adapters/polymarket/src/websocket/client.rs:87
}
impl WsSubscriptionHandle {
/// Sends a market subscribe command to the handler.
pub async fn subscribe_market(&self, asset_ids: Vec<String>) -> anyhow::Result<()> {
self.cmd_tx
.read()
.await
.send(HandlerCommand::SubscribeMarket(asset_ids))
.map_err(|e| anyhow::anyhow!("Failed to send SubscribeMarket: {e}"))
}
/// Sends a market unsubscribe command to the handler.
pub async fn unsubscribe_market(&self, asset_ids: Vec<String>) -> anyhow::Result<()> {
self.cmd_tx
.read()
.await
.send(HandlerCommand::UnsubscribeMarket(asset_ids))
.map_err(|e| anyhow::anyhow!("Failed to send UnsubscribeMarket: {e}"))
}
// Constructs a handle around a raw command sender. Test-only: lets unit
// tests observe the commands the handle emits without spinning up the real
// feed handler.
#[cfg(test)]
pub(crate) fn from_sender(sender: tokio::sync::mpsc::UnboundedSender<HandlerCommand>) -> Self {
Self {
cmd_tx: Arc::new(tokio::sync::RwLock::new(sender)),
}
}
}
/// Provides a WebSocket client for the Polymarket CLOB API.
///
/// A single instance targets one channel (market or user). Use
/// [`PolymarketWebSocketClient::new_market`] for public market data and
/// [`PolymarketWebSocketClient::new_user`] for authenticated order/trade streams.View on GitHub (pinned to 18893faf8b)
Solutions
- Guard the call with a connected/is_active check
- If the client is down, the subscription is already gone — skip unsubscribe_market() and return Ok
- Call connect() first if you need the client live again, then unsubscribe
- Investigate why the handler task exited via its logs
Example fix
// before
client.unsubscribe_market(asset_ids).await?;
// after
if client.is_active() {
client.unsubscribe_market(asset_ids).await?;
} // else: subscription died with the session, nothing to unsubscribe Defensive patterns
Strategy: try-catch
Validate before calling
if client.is_active() {
client.unsubscribe_market(asset_ids).await?;
} Try / catch
if let Err(e) = client.unsubscribe_market(asset_ids).await {
// handler gone means the venue subscription is gone too; safe to ignore on shutdown
log::debug!("unsubscribe skipped, handler not running: {e:#}");
} Prevention
- Skip unsubscribe when the client is already disconnected — nothing to unsubscribe
- Centralize lifecycle (connect/disconnect/subscribe) in one owning task
- Treat this error as benign during shutdown paths
- Monitor handler task liveness to distinguish real failures from benign ones
When it happens
Trigger: Calling unsubscribe_market() after disconnect(), after the handler task terminated (panic or fatal connection error), or concurrently with a reconnect that replaces the handler task.
Common situations: Cleanup/shutdown code unsubscribing after the client was already disconnected; handler died earlier from a network outage; test harness dropping the client while an unsubscribe is in flight.
Related errors
- Failed to send SubscribeMarket: {e}
- Failed to replay SubscribeUser: {e}
- Failed to send SubscribeUser: {e}
- Failed to send SetClient command: {e}
- unsupported Derive public WS channel `{}`
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/73eceefbe336d4bb.
Report an issue: GitHub.