nautechsystems/nautilus_trader · error

failed to register Tardis stream task: {e}

Error message

failed to register Tardis stream task: {e}

What it means

Raised in spawn_ws_task when the actor task set refuses to register the Tardis WebSocket stream task. It means the task manager (generation-based supervisor) is not in a state that accepts new tasks — typically it is shutting down or the generation has ended.

Source

Thrown at crates/adapters/tardis/src/data.rs:252

                    Err(e) => {
                        if cancel.is_cancelled() {
                            break;
                        }

                        log::warn!(
                            "Failed to reconnect to Tardis Machine: {e}, retrying in {}s",
                            reconnect_delay.as_secs()
                        );
                    }
                }
            }

            connected.store(false, Ordering::Release);
        };

        self.tasks
            .spawn(future)
            .map_err(|e| anyhow::anyhow!("failed to register Tardis stream task: {e}"))?;
        Ok(())
    }

    /// Runs a single WebSocket session: starts heartbeat, processes messages,
    /// and returns whether the caller should attempt reconnection.
    async fn run_ws_session(
        ws_stream: tokio_tungstenite::WebSocketStream<
            tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>,
        >,
        cancel: &CancellationToken,
        sender: &tokio::sync::mpsc::UnboundedSender<DataEvent>,
        instrument_map: &AHashMap<TardisInstrumentKey, Arc<TardisInstrumentMiniInfo>>,
        book_snapshot_output: &BookSnapshotOutput,
        extract_bbo_as_quotes: bool,
    ) -> bool {
        let (mut writer, mut reader) = ws_stream.split();

        let heartbeat_token = cancel.child_token();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure disconnect() has fully completed (finish_shutdown awaited) before calling connect again.
  2. Avoid concurrent connect/disconnect calls; serialize lifecycle operations.
  3. Check that a prior shutdown didn't leave the task set closed; recreate/restart the client if so.
  4. Retry the connect after the task set starts a new generation.
Defensive patterns

Strategy: try-catch

Validate before calling

// Only connect when fully disconnected and not shutting down
if client.is_connected.load(Ordering::Acquire) || shutdown_in_progress() {
    anyhow::bail!("cannot connect: client busy or shutting down");
}

Try / catch

match client.connect() {
    Err(e) if e.to_string().contains("failed to register Tardis stream task") => {
        tokio::time::sleep(Duration::from_millis(200)).await;
        client.connect().await?; // retry after shutdown settles
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling connect which invokes spawn_ws_task while the task set is finishing shutdown, already closed, or between generations, so tasks.spawn(future) fails.

Common situations: Calling connect() concurrently with disconnect(); reconnecting immediately after disconnect before shutdown completes; racing connect calls from multiple threads.

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