nautechsystems/nautilus_trader · error · anyhow::Error

Failed to start Polymarket session generation: {e}

Error message

Failed to start Polymarket session generation: {e}

What it means

`connect_client` similarly restarts the session task group (WebSocket dispatch, polling) via `session_tasks.start_generation()` when it is not open. Failure of that restart — because the previous generation is still terminating or the group rejects a new generation — is wrapped in this error. Note the message says 'session generation' vs 'task generation' for the pending group (error 3554).

Source

Thrown at crates/adapters/polymarket/src/execution/lifecycle.rs:652

        }

        log::info!("Connecting Polymarket execution client");

        if !self.pending_tasks.is_open() || !self.session_tasks.is_open() {
            self.teardown_partial_connect().await?;
        }

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

        if !self.session_tasks.is_open() {
            self.await_session_tasks().await?;
            self.session_tasks.start_generation().map_err(|e| {
                anyhow::anyhow!("Failed to start Polymarket session generation: {e}")
            })?;
        }
        self.stopping.store(false, Ordering::Release);
        let ws_shutdown = self.ws_client.shutdown_handle();
        let stopping = Arc::clone(&self.stopping);
        let setup_guard =
            TaskGroupGuard::new(&[&self.session_tasks, &self.pending_tasks], move || {
                stopping.store(true, Ordering::Release);
                ws_shutdown.begin_shutdown();
            });

        let version = self
            .http_client
            .get_version()
            .await
            .context("failed to query Polymarket CLOB protocol version")?
            .version;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure await_session_tasks fully completes (including abort) before start_generation; increase TASK_ABORT_TIMEOUT if needed
  2. Check the wrapped `{e}` for the task-group rejection cause
  3. Serialize connection attempts so a second connect cannot race the first teardown
  4. Restart/recreate the client if the session task group cannot accept a new generation

Example fix

// before: racing teardown and reconnect
tokio::join!(adapter.disconnect(), adapter.connect());
// after: sequential lifecycle
tokio::join!(adapter.disconnect());
adapter.connect().await?;
Defensive patterns

Strategy: retry

Validate before calling

// serialize lifecycle transitions
let _guard = lifecycle_lock.lock().await;

Try / catch

match adapter.connect().await {
    Err(e) if e.to_string().contains("session generation") => {
        tokio::time::sleep(backoff).await;
        adapter.connect().await?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: connect_client after session_tasks was closed by begin_shutdown, when start_generation fails; await_session_tasks returned but the group has not fully released its previous generation.

Common situations: Reconnect during shutdown race; abort timeout still in flight; consecutive connect calls where the second collides with the first's teardown.

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