nautechsystems/nautilus_trader · error

unsubscribe_market() requires a market-channel client (creat

Error message

unsubscribe_market() requires a market-channel client (created with new_market())

What it means

unsubscribe_market sends a market-channel unsubscribe command and is only valid on a client configured for the market channel. On a user-channel client there is no asset-id market subscription to remove, so the call is rejected up front.

Source

Thrown at crates/adapters/polymarket/src/websocket/client.rs:544

        }
        self.cmd_tx
            .read()
            .await
            .send(HandlerCommand::SubscribeMarket(asset_ids))
            .map_err(|e| anyhow::anyhow!("Failed to send SubscribeMarket: {e}"))
    }

    /// Remove asset IDs from the active subscription set.
    ///
    /// The IDs are dropped from the reconnect set so they will not be
    /// re-subscribed after a reconnect. No wire message is sent.
    ///
    /// # Errors
    ///
    /// Returns an error if called on a user-channel client (incompatible channel).
    pub async fn unsubscribe_market(&self, asset_ids: Vec<String>) -> anyhow::Result<()> {
        if self.channel != WsChannel::Market {
            anyhow::bail!(
                "unsubscribe_market() requires a market-channel client (created with new_market())"
            );
        }
        self.cmd_tx
            .read()
            .await
            .send(HandlerCommand::UnsubscribeMarket(asset_ids))
            .map_err(|e| anyhow::anyhow!("Failed to send UnsubscribeMarket: {e}"))
    }

    /// Authenticate and subscribe to the user channel.
    ///
    /// # Errors
    ///
    /// Returns an error if called on a market-channel client (no credentials available).
    pub async fn subscribe_user(&self) -> anyhow::Result<()> {
        if self.channel != WsChannel::User {
            anyhow::bail!(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Only call unsubscribe_market on clients created with new_market(); use unsubscribe_user for user-channel clients
  2. Track the channel of each client and branch teardown logic on it
  3. Check the channel field before calling to avoid the error

Example fix

// before
client.unsubscribe_market(asset_ids).await?;
client.unsubscribe_user().await?;
// after
match client.channel() {
    WsChannel::Market => client.unsubscribe_market(asset_ids).await?,
    WsChannel::User => client.unsubscribe_user().await?,
}
Defensive patterns

Strategy: validation

Validate before calling

if client.channel() == WsChannel::Market {
    client.unsubscribe_market(asset_ids).await?;
}

Prevention

When it happens

Trigger: Calling unsubscribe_market(asset_ids) on a client built with new_user() (WsChannel::User), typically to tear down subscriptions that were never made on that client.

Common situations: Cleanup/shutdown code that calls both unsubscribe_market and unsubscribe_user on every client regardless of channel; wrong client instance passed to a teardown helper.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/621dc1c3a4980850. Report an issue: GitHub.