nautechsystems/nautilus_trader · error

Failed to start Derive data session generation: {e}

Error message

Failed to start Derive data session generation: {e}

What it means

During the Derive data client's `connect`, if the session/pending task groups are not in a clean state, it tears down partial state and starts a new generation for `session_tasks`. This error wraps a failure of that generation start, blocking the data client from establishing its WebSocket session task set.

Source

Thrown at crates/adapters/derive/src/data.rs:745

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

        // Completes the async teardown deferred by sync reset()/stop().
        if self.cancellation_token.is_cancelled()
            || !self.session_tasks.is_open()
            || !self.pending_tasks.is_open()
        {
            self.teardown_partial_connect().await?;
            self.cancellation_token = CancellationToken::new();
            self.session_tasks.start_generation().map_err(|e| {
                anyhow::anyhow!("Failed to start Derive data session generation: {e}")
            })?;
            self.pending_tasks
                .start_generation()
                .map_err(|e| anyhow::anyhow!("Failed to start Derive data task generation: {e}"))?;
        }
        let cancellation_token = self.cancellation_token.clone();
        let ws_shutdown = self.ws_client.shutdown_handle();
        let setup_guard =
            TaskGroupGuard::new(&[&self.session_tasks, &self.pending_tasks], move || {
                cancellation_token.cancel();
                ws_shutdown.begin_shutdown();
            });

        if !self.config.currencies.is_empty() {
            self.provider
                .load_all(None)
                .await
                .context("failed to load Derive instruments")?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the wrapped `{e}` from start_generation for the root cause.
  2. Await full teardown (`teardown_partial_connect`) / prior disconnect before reconnecting.
  3. Avoid concurrent connect() calls on the same data client; serialize lifecycle calls.
  4. Recreate the data client if its task groups were permanently shut down.
  5. Check that the tokio runtime isn't being dropped mid-connect.

Example fix

// before
data_client.connect().await?; // after a failed earlier connect
// after
data_client.disconnect().await?; // ensure clean state
data_client.connect().await?;
Defensive patterns

Strategy: retry

Validate before calling

// Only connect when previous lifecycle ended:
if !data_client.is_connected() && prior_connect_finished { data_client.connect().await?; }

Try / catch

match data_client.connect().await {
    Err(e) if e.to_string().contains("session generation") => {
        tokio::time::sleep(BACKOFF).await;
        data_client.connect().await.context("reconnect failed")?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `connect()` on the Derive data client when `session_tasks` is not open/empty and `start_generation()` returns Err (group shut down, generation state invalid, prior teardown incomplete).

Common situations: Reconnecting after an aborted connect whose teardown didn't fully complete; concurrent connect attempts on the same data client; runtime shutdown racing connection setup.

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