nautechsystems/nautilus_trader · error · anyhow::Error
Failed to start Polymarket task generation: {e}
Error message
Failed to start Polymarket task generation: {e} What it means
`connect_client` lazily starts a new generation of the pending (execution) task group when it is not open. Before restarting, it drains prior tasks via await_pending_tasks. If `pending_tasks.start_generation()` fails (the task group runtime rejects the restart — e.g. still shutting down or already running), this error wraps the cause.
Source
Thrown at crates/adapters/polymarket/src/execution/lifecycle.rs:646
}
pub(super) async fn connect_client(&mut self) -> anyhow::Result<()> {
if self.core.is_connected() && self.pending_tasks.is_open() && self.session_tasks.is_open()
{
return Ok(());
}
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 = selfView on GitHub (pinned to 18893faf8b)
Solutions
- Wait for the pending task group's shutdown/abort to fully complete before reconnecting (increase abort timeout if needed)
- Inspect the wrapped `{e}` for the task-group's rejection reason
- Avoid rapid connect/disconnect cycles; add backoff between reconnect attempts
- Recreate the execution client if the task group is permanently wedged
Example fix
// before: immediate reconnect loop
loop { adapter.connect().await?; }
// after: back off between generations
loop {
adapter.connect().await?;
tokio::time::sleep(Duration::from_secs(1)).await;
} Defensive patterns
Strategy: retry
Validate before calling
// add reconnect backoff to avoid racing previous generation shutdown let delay = Duration::from_millis(500 * attempts);
Try / catch
match adapter.connect().await {
Err(e) if e.to_string().contains("task generation") => {
tokio::time::sleep(backoff).await;
adapter.connect().await?;
}
other => other?,
} Prevention
- Use exponential backoff on reconnects
- Ensure abort timeouts complete before starting a new generation
- Log the wrapped error chain to identify task-group rejection causes
When it happens
Trigger: First connect or reconnect when pending_tasks is closed; start_generation called while the previous generation has not fully terminated (await_pending_tasks returned but the group still rejects a new generation).
Common situations: Rapid reconnect loops where the abort timeout has not yet completed; task-group runtime misconfiguration; calling connect after a failed teardown left the group in a half-shutdown state.
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
- Failed to start Betfair data session tasks: {e}
- Failed to start Betfair data command tasks: {e}
- Failed to start Polymarket session generation: {e}
- Already running
- Failed to start AX execution session generation: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/eb982513a7cebf5a.
Report an issue: GitHub.