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
- Ensure disconnect() has fully completed (finish_shutdown awaited) before calling connect again.
- Avoid concurrent connect/disconnect calls; serialize lifecycle operations.
- Check that a prior shutdown didn't leave the task set closed; recreate/restart the client if so.
- 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
- Await disconnect() completion before reconnecting.
- Guard connect/disconnect with a mutex or actor message to prevent races.
- Never share a client instance across concurrent lifecycle callers.
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
- std::mem::take(&mut self.shutdown_errors).join("; ")
- Binance Spot public JSON stream pool is shutting down
- Failed to start Spot public JSON WS bytes task: {e}
- Failed to start Spot public JSON WS handler task: {e}
- No active WebSocket client
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e4bc145d16a9dc21.
Report an issue: GitHub.