nautechsystems/nautilus_trader · error · anyhow::Error
L3 WebSocket failed to become active: {e}
Error message
L3 WebSocket failed to become active: {e} What it means
KrakenSpotDataClient::subscribe_l3_book spawns a task that must wait for the dedicated L3 WebSocket to become active before subscribing; `wait_until_active(10.0)` polls `is_active()` for 10 seconds and returns `KrakenWsError::ConnectionError("WebSocket connection timeout after 10 seconds")` if it never does. The adapter wraps that timeout in this message. It means the L3 WebSocket connection (a separate client spawned for Level 3 data) never reached the active state within the 10s budget.
Source
Thrown at crates/adapters/kraken/src/data/spot.rs:347
self.l3_handler_task = self.spawn_l3_handler_task(ws_l3.clone(), false);
self.ws_l3 = Some(ws_l3);
} else if handler_finished && let Some(ws_l3) = self.ws_l3.as_ref() {
let ws_l3 = ws_l3.clone();
self.l3_handler_task = self.spawn_l3_handler_task(ws_l3, true);
}
let ws_l3 = self
.ws_l3
.as_ref()
.expect("ws_l3 initialized above")
.clone();
self.spawn_ws(
async move {
ws_l3
.wait_until_active(10.0)
.await
.map_err(|e| anyhow::anyhow!("L3 WebSocket failed to become active: {e}"))?;
ws_l3
.wait_until_authenticated(10.0)
.await
.map_err(|e| anyhow::anyhow!("L3 WebSocket failed to authenticate: {e}"))?;
ws_l3
.subscribe_book_l3(symbol_ustr, depth)
.await
.map_err(|e| anyhow::anyhow!("{e}"))
},
"subscribe l3 book",
);
Ok(())
}
fn spawn_l3_handler_task(
&self,
handler_client: KrakenSpotWebSocketClient,View on GitHub (pinned to 18893faf8b)
Solutions
- Verify basic connectivity to Kraken's v2 WebSocket endpoint (curl/TLS handshake, proxy reachability) and fix network/proxy settings.
- Check logs for the earlier 'L3 WebSocket connect failed' error from the spawned L3 handler task — fix that root cause first.
- If behind a corporate proxy, set config.proxy_url correctly for the L3 client.
- Retry the subscription; transient Kraken connection slowness can exceed the fixed 10s window.
- Confirm the runtime (tokio) is not starved — a blocked executor can prevent the handler task from completing the handshake.
Example fix
// before
self.spawn_ws(async move {
ws_l3.wait_until_active(10.0).await
.map_err(|e| anyhow::anyhow!("L3 WebSocket failed to become active: {e}"))?;
...
});
// after (caller retries with backoff on transient network issues)
match client.subscribe_book_deltas(&cmd) {
Err(e) if e.to_string().contains("failed to become active") => {
tokio::time::sleep(Duration::from_secs(2)).await;
client.subscribe_book_deltas(&cmd)?;
}
Err(e) => return Err(e),
Ok(()) => {}
} Defensive patterns
Strategy: retry
Validate before calling
// pre-check connectivity to Kraken v2 WS before subscribing
async fn kraken_ws_reachable() -> bool {
tokio::net::TcpStream::connect("ws.kraken.com:443").await.is_ok()
}
if !kraken_ws_reachable().await { /* defer or alert before subscribe_l3_book */ } Try / catch
match client.subscribe_book_deltas(&cmd) {
Err(e) if e.to_string().contains("failed to become active") => {
// wait and retry with backoff; check handler-task logs for connect failure
tokio::time::sleep(Duration::from_secs(2)).await;
}
Err(e) => return Err(e),
Ok(()) => {}
} Prevention
- Verify network/proxy reachability to Kraken's v2 WebSocket endpoint before starting L3 sessions
- Monitor adapter logs for 'L3 WebSocket connect failed' to catch root-cause connect errors early
- Avoid starting L3 subscriptions on a saturated tokio runtime
- Provide config.proxy_url when operating behind a corporate proxy
When it happens
Trigger: Calling subscribe_book_deltas (L3 mode) when the underlying L3 KrakenSpotWebSocketClient fails to connect — network outage, DNS/proxy failure, Kraken endpoint down, or the spawned L3 handler task's connect() failed so `is_active()` never turns true within 10 seconds.
Common situations: No internet or firewall/proxy blocking wss://ws.kraken.com/v2; invalid proxy_url configured; Kraken WebSocket outage or rate-limiting new connections; machine clock/scheduling stalls under heavy backtest/live load so the 10s window elapses before the handshake completes.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- L3 WebSocket failed to authenticate: {e}
- {e}
- WS user data subscription timed out
- std::mem::take(&mut self.shutdown_errors).join("; ")
- WebSocket output receiver not available
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ed3c73a3b3303249.
Report an issue: GitHub.