nautechsystems/nautilus_trader · warning

RTDS connect was canceled by shutdown

Error message

RTDS connect was canceled by shutdown

What it means

During RTDS connect, after retained tasks finish, the code checks the shutdown generation counter; if a shutdown happened concurrently (generation advanced), the in-flight connect is stale and is canceled with this error. It prevents a connect from resurrecting resources after shutdown began.

Source

Thrown at crates/adapters/polymarket/src/rtds.rs:552

            }
        }

        self.inner.last_emitted_timestamps_ms.remove(&parsed.key);
        entry.remove();
        Ok(true)
    }

    pub(crate) async fn connect(&self) -> anyhow::Result<()> {
        let generation = *self.inner.shutdown_generation.lock();

        if self.inner.closing.load(Ordering::Acquire) {
            self.finish_retained_tasks().await?;
        }

        {
            let current_generation = self.inner.shutdown_generation.lock();
            if *current_generation != generation {
                anyhow::bail!("RTDS connect was canceled by shutdown");
            }
            self.inner.closing.store(false, Ordering::Release);
        }

        self.ensure_reconcile_worker();
        self.reconcile_once(false).await?;

        let current_generation = self.inner.shutdown_generation.lock();
        if *current_generation != generation || self.inner.closing.load(Ordering::Acquire) {
            anyhow::bail!("RTDS connect was canceled by shutdown");
        }
        Ok(())
    }

    async fn finish_retained_tasks(&self) -> anyhow::Result<()> {
        let Some(tasks) = self.task_slots() else {
            if let Some(ws) = self.current_ws() {
                ws.notify_closed();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Stop calling connect() once shutdown has been initiated; check client state first
  2. Serialize connect/shutdown calls (e.g. hold a lock or a single supervision task)
  3. Treat this error as a benign cancellation: log and return instead of retrying

Example fix

// before
tokio::join!(client.connect(), async { client.shutdown().await });
// after
client.shutdown().await?;
// then no further connect() calls on this client instance
Defensive patterns

Strategy: try-catch

Type guard

fn is_shutdown_canceled(e: &anyhow::Error) -> bool {
    e.to_string() == "RTDS connect was canceled by shutdown"
}

Try / catch

match client.connect().await {
    Err(e) if e.to_string() == "RTDS connect was canceled by shutdown" => {
        log::info!("connect canceled by shutdown; ignoring");
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling connect() concurrently with shutdown()/disconnect(); a shutdown initiated while a reconnect loop was mid-connect; races from dropping the client while auto-reconnect is active.

Common situations: App teardown racing a background reconnect; calling connect from another task right as the client is shut down; rapid connect/disconnect cycles.

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