nautechsystems/nautilus_trader · error

Failed to start Deribit task generation: {e}

Error message

Failed to start Deribit task generation: {e}

What it means

`connect` must open a new pending-task generation before running order/trade tasks. If `start_generation` on the task manager fails (typically called on a manager not in a startable state, e.g. still shutting down or already open), the error at execution.rs:478 is returned. The connect attempt aborts before any WebSocket work for trading tasks begins.

Source

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

        self.core.set_stopped();
        self.core.set_disconnected();
        self.abort_session_tasks();
        self.abort_pending_tasks();
        log::info!("Stopped: client_id={}", self.core.client_id);
        Ok(())
    }

    async fn connect(&mut self) -> anyhow::Result<()> {
        if self.core.is_connected() && self.pending_tasks.is_open() && self.session_tasks.is_open()
        {
            return Ok(());
        }

        if !self.pending_tasks.is_open() {
            self.await_pending_tasks().await?;
            self.pending_tasks
                .start_generation()
                .map_err(|e| anyhow::anyhow!("Failed to start Deribit task generation: {e}"))?;
        }

        if !self.session_tasks.is_open() || !self.session_tasks.is_empty() {
            self.abort_session_tasks();

            if self.ws_client.is_active() {
                self.ws_client
                    .close()
                    .await
                    .context("failed to close stale Deribit WebSocket")?;
            }
            self.await_session_tasks().await?;
            self.session_tasks
                .start_generation()
                .map_err(|e| anyhow::anyhow!("Failed to start Deribit session generation: {e}"))?;
        } else if self.ws_client.is_active() {
            self.ws_client
                .close()

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure only one `connect()` runs at a time; serialize connects behind a mutex/single owner.
  2. After shutdown errors, call `abort_pending_tasks()` before retrying `connect()`.
  3. Back off and retry the connect after a short delay so the task manager exits its shutdown state.
  4. Check application code for reconnect loops without backoff that race the shutdown window.

Example fix

// before
let (a, b) = tokio::join!(client.connect(), client.connect());

// after
static CONNECT: tokio::sync::Mutex<()> = tokio::sync::Mutex::const_new(());
let _guard = CONNECT.lock().await;
client.connect().await?;
Defensive patterns

Strategy: retry

Validate before calling

// Guard against concurrent connects before calling the API
let _guard = connect_mutex.lock().await;
// proceed with client.connect().await

Try / catch

match client.connect().await {
    Err(e) if e.to_string().contains("Failed to start Deribit task generation") => {
        client.abort_pending_tasks();
        tokio::time::sleep(Duration::from_millis(500)).await;
        client.connect().await?;
    }
    other => other.map(|_| ()),
}

Prevention

When it happens

Trigger: Calling `connect()` while the pending-task manager is mid-shutdown from a previous session; concurrent `connect()` calls racing on the same task manager; a previous `finish_shutdown` timeout left the manager in a bad state.

Common situations: Reconnect storms on unstable networks calling connect repeatedly; framework code invoking connect from multiple tasks without synchronization; recovery after the 'Failed to terminate Deribit execution tasks' error without aborting tasks first.

Related errors


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