nautechsystems/nautilus_trader · error

subscribe_user() requires a user-channel client (created wit

Error message

subscribe_user() requires a user-channel client (created with new_user())

What it means

subscribe_user sends authenticated subscription commands derived from stored API credentials and is only valid on a client configured for the user channel (new_user). A market-channel client has no credentials, so the call cannot work and is rejected.

Source

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

            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!(
                "subscribe_user() requires a user-channel client (created with new_user())"
            );
        }
        self.cmd_tx
            .read()
            .await
            .send(HandlerCommand::SubscribeUser)
            .map_err(|e| anyhow::anyhow!("Failed to send SubscribeUser: {e}"))?;
        // Set only after the command is successfully enqueued so a failed send does not
        // leave user_subscribed=true and cause an unintended replay on the next connect().
        self.user_subscribed.store(true, Ordering::Relaxed);
        Ok(())
    }

    /// Returns a cloneable subscription handle for use in spawned tasks.
    #[must_use]
    pub fn clone_subscription_handle(&self) -> WsSubscriptionHandle {
        WsSubscriptionHandle {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Build the client with PolymarketWebSocketClient::new_user() with valid API credentials, then call subscribe_user()
  2. Maintain two clients: new_market() for books and new_user() for order/fill updates
  3. Check the channel before subscribing

Example fix

// before
let client = PolymarketWebSocketClient::new_market().await?;
client.subscribe_user().await?;
// after
let client = PolymarketWebSocketClient::new_user(api_creds).await?;
client.subscribe_user().await?;
Defensive patterns

Strategy: validation

Validate before calling

if client.channel() == WsChannel::User {
    client.subscribe_user().await?;
}

Prevention

When it happens

Trigger: Calling subscribe_user() on a client built with new_market() (WsChannel::Market), e.g. expecting order/fill updates from a book-data connection.

Common situations: Using one shared market-data client to also receive private order events; forgetting that Polymarket requires a separate authenticated user-channel connection with API keys.

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/f249d8b7b8c44a9a. Report an issue: GitHub.