nautechsystems/nautilus_trader · error

subscription confirmation failed: {e}

Error message

subscription confirmation failed: {e}

What it means

The Deribit execution client subscribes to user order, trade, and portfolio channels during connect; this error is raised when the WebSocket client does not receive subscription confirmations within the 30-second timeout. On failure it unsubscribes from all three channels so a reconnect retry re-sends the subscribe requests cleanly.

Source

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

            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 {
                // Roll back subscription state so a retry re-sends subscribe requests
                let _ = self.ws_client.unsubscribe_user_orders().await;
                let _ = self.ws_client.unsubscribe_user_trades().await;
                let _ = self.ws_client.unsubscribe_user_portfolio().await;
                anyhow::bail!("subscription confirmation failed: {e}");
            }

            log::debug!("Subscribed to user order, trade, and portfolio updates");

            // Spawn stream handler to dispatch WebSocket messages to the execution engine
            let stream = self.ws_client.stream()?;
            self.spawn_stream_handler(stream)?;

            Ok::<(), anyhow::Error>(())
        }
        .await;

        if let Err(e) = session_result {
            if let Err(teardown_error) = self.teardown_partial_connect().await {
                return Err(e.context(format!(
                    "Deribit execution startup teardown failed: {teardown_error}"
                )));
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify Deribit API credentials are valid and test auth separately before connecting
  2. Check network connectivity and any proxy/firewall that may block or delay WebSocket frames
  3. Check Deribit status (outages/degraded service) and retry connect after unsubscribed rollback
  4. Increase tolerance by retrying connect — subscription state is rolled back so a retry re-subscribes correctly

Example fix

// before
let client = DeribitExecutionClient::new(...); // connect() may bail on confirmation timeout
client.connect().await?;
// after
for attempt in 0..3 {
    match client.connect().await {
        Ok(()) => break,
        Err(e) if e.to_string().contains("subscription confirmation failed") && attempt < 2 => {
            log::warn!("retrying connect after subscription failure: {e}");
            tokio::time::sleep(Duration::from_secs(5)).await;
        }
        Err(e) => return Err(e),
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// Before connecting, verify credentials and reachability
let creds = std::env::var("DERIBIT_API_KEY")?;
assert!(!creds.is_empty());
// optionally ping Deribit REST: GET https://www.deribit.com/api/v2/public/test

Try / catch

match client.connect().await {
    Err(e) if e.to_string().contains("subscription confirmation failed") => retry_with_backoff(3),
    other => other,
}

Prevention

When it happens

Trigger: Calling connect when the Deribit WebSocket does not confirm all subscriptions (private/orders, private/trades, private/portfolio) within 30 seconds — typically due to network issues, slow Deribit API response, or failed authentication preventing private channel subscription.

Common situations: Deribit outage or degraded WebSocket service; expired API credentials so private channels are rejected; corporate proxy/firewall dropping or delaying WS frames; very slow network causing confirmation to arrive after the 30s window.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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