nautechsystems/nautilus_trader · error
Failed to start Coinbase WebSocket handler task: {e}
Error message
Failed to start Coinbase WebSocket handler task: {e} What it means
connect() spawns the long-running WebSocket handler task with tokio::spawn; if the spawn call itself returns Err (the runtime cannot start the task), the adapter rolls back out_rx and returns this error.
Source
Thrown at crates/adapters/coinbase/src/websocket/client.rs:377
log::debug!("Output channel closed: {e}");
break;
}
}
Some(msg) => {
if let Err(e) = out_tx.send(msg) {
log::debug!("Output channel closed: {e}");
break;
}
}
None => {
log::debug!("Feed handler stopped");
break;
}
}
}
}) {
self.out_rx = None;
anyhow::bail!("Failed to start Coinbase WebSocket handler task: {e}");
}
Ok(())
}
/// Subscribes to a channel for the given product IDs.
pub async fn subscribe(
&self,
channel: CoinbaseWsChannel,
product_ids: &[Ustr],
) -> anyhow::Result<()> {
let jwt = if channel.requires_auth() {
let credential = self
.credential
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Credentials required for {channel}"))?;
Some(credential.build_ws_jwt()?)
} else {View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure connect() is awaited inside a live tokio runtime (e.g. #[tokio::main] or a Handle)
- Delay adapter shutdown until WebSocket disconnect() finishes
- If spawning from a plain thread, obtain a tokio::runtime::Handle and use handle.spawn
Example fix
// before
std::thread::spawn(|| ws.connect().await); // no runtime
// after
let handle = tokio::runtime::Handle::current();
handle.spawn(async move { ws.connect().await }); Defensive patterns
Strategy: try-catch
Validate before calling
// ensure a runtime exists before constructing/connecting the client
let handle = tokio::runtime::Handle::try_current()
.map_err(|_| "Coinbase WebSocket requires a tokio runtime")?; Try / catch
match tokio::runtime::Handle::try_current() {
Ok(h) => { /* safe to call connect().await within runtime */ }
Err(_) => { /* build/enter a runtime or use handle.spawn */ }
} Prevention
- Only use async adapter APIs inside a Tokio runtime
- Complete adapter shutdown before runtime teardown
- Use runtime Handle::spawn for cross-thread usage
When it happens
Trigger: tokio::spawn fails — practically only when there is no active Tokio runtime context or the runtime is shutting down while connect() is invoked.
Common situations: Calling connect() outside an async runtime (blocking context without a runtime handle); application shutdown tearing down the runtime while the adapter reconnects; blocking the runtime so shutdown aborts spawn.
Related errors
- failed to finish Binance Futures data command tasks: {e}
- Failed to start Hyperliquid WebSocket handler task: {e}
- Failed to start Lighter WebSocket handler task: {e}
- Failed to start Polymarket WebSocket handler task: {e}
- Failed to send SetDepth10Sub command: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5f48baba17146a5d.
Report an issue: GitHub.