nautechsystems/nautilus_trader · error
Cannot connect while previous WebSocket handler task is stil
Error message
Cannot connect while previous WebSocket handler task is still running
What it means
`connect` enforces that no previous WebSocket handler task is still alive before starting a new connection. If a prior handler task exists and has not finished (still connected/subscribed), starting another would double-handle messages, so the call fails with this error.
Source
Thrown at crates/adapters/okx/src/websocket/client.rs:600
}
/// Gets the current VIP level.
pub fn vip_level(&self) -> OKXVipLevel {
let level = self.vip_level.load(Ordering::Relaxed);
OKXVipLevel::from(level)
}
/// Connect to the OKX WebSocket server.
///
/// # Errors
///
/// Returns an error if the connection process fails.
pub async fn connect(&mut self) -> anyhow::Result<()> {
let connect_lock = Arc::clone(&self.connect_lock);
let _connect_guard = connect_lock.lock().await;
if !self.handler_tasks.is_empty() && !self.handler_tasks.all_finished() {
anyhow::bail!("Cannot connect while previous WebSocket handler task is still running");
}
if !self.handler_tasks.is_open() || !self.handler_tasks.is_empty() {
self.handler_tasks.begin_shutdown();
self.handler_tasks
.finish_shutdown(Duration::from_secs(2), Duration::from_secs(2))
.await
.map_err(|e| anyhow::anyhow!("Previous WebSocket handler failed: {e}"))?;
self.handler_tasks.start_generation().map_err(|e| {
anyhow::anyhow!("Failed to start WebSocket handler task generation: {e}")
})?;
}
let handler_spawner = self.handler_tasks.spawner().map_err(|e| {
anyhow::anyhow!("Failed to acquire WebSocket handler task spawner: {e}")
})?;
let handler_abort = CancellationToken::new();
*self.handler_abort.lock() = handler_abort.clone();
let mut rollback = ConnectRollback {View on GitHub (pinned to 18893faf8b)
Solutions
- Call `disconnect()` (and await it) before calling `connect()` again.
- Reuse the existing connected client instead of reconnecting.
- Ensure `all_finished()` becomes true by letting prior tasks shut down (the client will auto-shutdown stale tasks only when not open); check `is_active` before connecting.
Example fix
// before
if !client.is_active() { client.connect().await?; } // stale handler may still run
// after
client.disconnect().await?;
client.connect().await?; Defensive patterns
Strategy: try-catch
Validate before calling
// only connect when no handler tasks are pending
if client.is_active() || !client.is_disconnected() {
// skip connect or disconnect first
} Try / catch
match client.connect().await {
Ok(()) => {},
Err(e) if e.to_string().contains("previous WebSocket handler task") => {
client.disconnect().await?;
client.connect().await?;
}
Err(e) => return Err(e),
} Prevention
- Always await disconnect() before reconnecting.
- Track connection state in your supervisor and call connect only from a disconnected state.
- Use a single owner task for the client lifecycle to avoid concurrent connect calls.
When it happens
Trigger: Calling `connect()` on an already-connected client, or reconnecting while a prior connection's handler tasks are still running (no prior `disconnect()`).
Common situations: Reconnect logic that calls `connect` again after a transient drop without awaiting `disconnect` first; test code or retry loops re-invoking `connect` on a live client.
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
- No active WebSocket client
- WebSocket output receiver not available
- Invalid `BarSpecification` for channel, was {bar_spec}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b4ca9fd93af35f02.
Report an issue: GitHub.