nautechsystems/nautilus_trader · critical

failed to authenticate WebSocket session: {e}

Error message

failed to authenticate WebSocket session: {e}

What it means

After connecting the execution WebSocket, the client authenticates the session with Deribit using the configured API credentials (`authenticate_session`). If Deribit rejects the auth (bad key/secret, expired signature, clock skew, revoked key), execution.rs:555 wraps the underlying error with this message and the connect fails — no order/trade subscriptions are made.

Source

Thrown at crates/adapters/deribit/src/execution.rs:555

        // Fetch initial account state
        let account_state = self
            .http_client
            .request_account_state(self.core.account_id)
            .await
            .context("failed to request account state")?;

        self.emitter.send_account_state(account_state);

        let session_result = async {
            self.ws_client
                .connect()
                .await
                .context("failed to connect WebSocket client for execution")?;

            self.ws_client
                .authenticate_session(DERIBIT_EXECUTION_SESSION_NAME)
                .await
                .map_err(|e| anyhow::anyhow!("failed to authenticate WebSocket session: {e}"))?;

            log::debug!("WebSocket client authenticated for execution");

            // Subscribe to user order and trade updates for all instruments
            self.ws_client
                .subscribe_user_orders()
                .await
                .map_err(|e| anyhow::anyhow!("failed to subscribe to user orders: {e}"))?;
            self.ws_client
                .subscribe_user_trades()
                .await
                .map_err(|e| anyhow::anyhow!("failed to subscribe to user trades: {e}"))?;
            self.ws_client
                .subscribe_user_portfolio()
                .await
                .map_err(|e| anyhow::anyhow!("failed to subscribe to user portfolio: {e}"))?;

            if let Err(e) = self.ws_client.wait_for_subscriptions_confirmed(30.0).await {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the API key/secret env vars are set correctly for the target environment (prod vs test) and trimmed of whitespace.
  2. Synchronize system clock (NTP) — Deribit auth is timestamp-sensitive.
  3. Check the wrapped inner error `{e}`: it usually states 'invalid credentials' vs 'authentication failed' to distinguish bad keys from expiry/clock issues.
  4. Regenerate the API key on the Deribit account and confirm required scopes for trading.
  5. Confirm the WebSocket URL matches the credential environment (www.deribit.com vs test.deribit.com).

Example fix

// before
let client = DeribitExecutionClient::new(..., "DERIBIT_API_KEY", old_secret, ...);

// after
let api_key = std::env::var("DERIBIT_TEST_API_KEY").expect("missing key");
let secret = std::env::var("DERIBIT_TEST_API_SECRET").expect("missing secret");
assert_eq!(ws_url.host_str(), Some("test.deribit.com"));
let client = DeribitExecutionClient::new(..., api_key, secret, ...);
Defensive patterns

Strategy: validation

Validate before calling

fn validate_deribit_creds(env: &str) -> Result<(), String> {
    let prefix = if env == "test" { "DERIBIT_TEST" } else { "DERIBIT" };
    let key = std::env::var(format!("{prefix}_API_KEY")).map_err(|_| "missing API key".to_string())?;
    let secret = std::env::var(format!("{prefix}_API_SECRET")).map_err(|_| "missing secret".to_string())?;
    if key.trim() != key || key.is_empty() || secret.is_empty() {
        return Err("key/secret empty or has whitespace".into());
    }
    // Deribit auth is timestamp-sensitive
    let skew = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap();
    Ok(())
}

Try / catch

if let Err(e) = client.connect().await {
    if e.to_string().contains("failed to authenticate WebSocket session") {
        // surface the inner Deribit error and fail fast on bad credentials
        log::error!("Deribit auth failed: {e:#}; check API key/secret, env (prod vs test), and clock sync");
        return Err(e);
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Wrong or missing DERIBIT API key/secret; revoked or expired API key; system clock drift breaking the HMAC/expiry-based Deribit auth; connecting to a environment (test/prod) with credentials from the other; keys lacking the required scopes.

Common situations: Rotated credentials but the adapter still reads old env vars; running on a box whose clock is a few minutes off; using production keys against test.deribit.com or vice versa; IP-restricted keys; copy-pasted key with whitespace/newline.

Understand the failure class

Related errors


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