nautechsystems/nautilus_trader · error · anyhow::Error

Credentials required for {channel}

Error message

Credentials required for {channel}

What it means

The Coinbase WebSocket client requires credentials when subscribing to authenticated channels (e.g. the `user` channel). If no credential was configured on the client, `subscribe` fails fast with this error before sending anything. Optional JWTs are only attached when credentials exist and the channel requires auth.

Source

Thrown at crates/adapters/coinbase/src/websocket/client.rs:393

        }) {
            self.out_rx = None;
            anyhow::bail!("Failed to start Coinbase WebSocket handler task: {e}");
        }

        Ok(())
    }

    /// Subscribes to a channel for the given product IDs.
    pub async fn subscribe(
        &self,
        channel: CoinbaseWsChannel,
        product_ids: &[Ustr],
    ) -> anyhow::Result<()> {
        let jwt = if channel.requires_auth() {
            let credential = self
                .credential
                .as_ref()
                .ok_or_else(|| anyhow::anyhow!("Credentials required for {channel}"))?;
            Some(credential.build_ws_jwt()?)
        } else {
            self.credential.as_ref().and_then(|c| c.build_ws_jwt().ok())
        };

        let sub = protect_subscription(CoinbaseWsSubscription {
            msg_type: CoinbaseWsAction::Subscribe,
            product_ids: product_ids.to_vec(),
            channel,
            jwt,
        })?;

        let channel_str = channel.as_ref();

        if product_ids.is_empty() {
            self.subscriptions.mark_subscribe(channel_str);
        } else {
            for product_id in product_ids {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Provide credentials when constructing the websocket client
  2. Subscribe only to public channels if you do not intend to authenticate
  3. Verify Coinbase API key environment variables are set and loaded into the credential
  4. Check that the channel you intend truly requires auth and use the correct public channel otherwise

Example fix

// before
let client = CoinbaseWsClient::new(None, url, rx).await?;
client.subscribe(CoinbaseWsChannel::User, &products).await?;
// after
let credential = CoinbaseCredentials::from_env()?;
let client = CoinbaseWsClient::new(Some(credential), url, rx).await?;
client.subscribe(CoinbaseWsChannel::User, &products).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn can_subscribe(channel: CoinbaseWsChannel, cred: &Option<CoinbaseCredentials>) -> Result<(), String> {
    if channel.requires_auth() && cred.is_none() {
        return Err(format!("channel {channel} requires credentials"));
    }
    Ok(())
}

Type guard

fn require_credentials<'a>(cred: &'a Option<CoinbaseCredentials>) -> Option<&'a CoinbaseCredentials> {
    cred.as_ref()
}

Try / catch

if let Err(e) = client.subscribe(CoinbaseWsChannel::User, &products).await {
    if e.to_string().starts_with("Credentials required") {
        eprintln!("configure Coinbase API credentials before user-channel subscribe");
    }
}

Prevention

When it happens

Trigger: Calling `subscribe` for a channel whose `requires_auth()` is true (such as CoinbaseWsChannel::User) while the client was constructed without credentials.

Common situations: Building the websocket client without passing Coinbase API key/secret/passphrase, then subscribing to the user channel for private fills/orders; env vars for Coinbase credentials unset or mistyped.

Related errors


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