nautechsystems/nautilus_trader · error

Failed to start Coinbase poll generation: {e}

Error message

Failed to start Coinbase poll generation: {e}

What it means

After finishing the previous shutdown in `prepare`, the adapter calls `start_generation` to open a new generation of poll tasks. Failure there (task-set state machine refused to start) is wrapped in this error.

Source

Thrown at crates/adapters/coinbase/src/data/poll.rs:144

                entry.cancel.cancel();
                // Replace the now-cancelled token so a later `resume()` can
                // spawn a fresh task that listens on a live token.
                entry.cancel = CancellationToken::new();
            }
        }

        self.tasks.begin_shutdown();
    }

    pub(crate) async fn prepare(&self) -> anyhow::Result<()> {
        if !self.tasks.is_open() {
            self.tasks
                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2))
                .await
                .map_err(|e| anyhow::anyhow!("Failed to finish Coinbase poll tasks: {e}"))?;
            self.tasks
                .start_generation()
                .map_err(|e| anyhow::anyhow!("Failed to start Coinbase poll generation: {e}"))?;
        }
        Ok(())
    }

    pub(crate) async fn finish_shutdown(&self) -> anyhow::Result<()> {
        self.tasks
            .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2))
            .await
            .map_err(|e| anyhow::anyhow!("Failed to finish Coinbase poll tasks: {e}"))?;
        Ok(())
    }

    /// Spawns polling tasks for every entry with at least one active flag.
    /// Called from `connect()` so subscriptions made before a
    /// `disconnect()` remain live after the client reconnects: the data
    /// engine suppresses duplicate subscribe commands, so the caller does
    /// not re-issue them.
    pub(crate) fn resume(&self) {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure connect is not called concurrently (serialize with a mutex or single task)
  2. Verify the preceding finish_shutdown fully completed before retrying
  3. Recreate the client instance if its task-set state is wedged
  4. Check logs for the inner `{e}` from start_generation

Example fix

// before
for sym in symbols {
    tokio::spawn(client.connect()); // concurrent connects
}
// after
client.connect().await?; // single serialized connect
Defensive patterns

Strategy: try-catch

Try / catch

match client.prepare().await {
    Err(e) if e.to_string().contains("Failed to start Coinbase poll generation") => {
        // state race: recreate client
        client = recreate_client(config).await?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: connect/prepare invoked when the task set's internal state forbids starting a new generation — e.g. shutdown not fully completed despite finish_shutdown returning Ok, or concurrent start_generation calls.

Common situations: Concurrent connect() calls from different tasks; reconnecting immediately after disconnect when generation counters are out of sync.

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