nautechsystems/nautilus_trader · error

Lighter WebSocket handler failed: {error}

Error message

Lighter WebSocket handler failed: {error}

What it means

This error is raised by connect_with_cancellation when the spawned Lighter WebSocket handler task terminates with an error while the initial connection is being established. The library joins the handler task after connecting and, if the join outcome is TaskJoinOutcome::Failed, the underlying error is propagated wrapped with this message. It indicates the background task that drives the WebSocket (read loop, auth, subscriptions) died during startup.

Source

Thrown at crates/adapters/lighter/src/websocket/client.rs:439

            "Lighter WebSocket initial connection cancelled",
        );

        if self.is_active() {
            log::warn!("Lighter WebSocket already connected");
            return Ok(());
        }

        if let Some(outcome) = finish_task(
            &mut self.task_handle,
            DISCONNECT_TIMEOUT,
            DISCONNECT_TIMEOUT,
        )
        .await
        {
            match outcome {
                TaskJoinOutcome::Completed(()) | TaskJoinOutcome::Aborted => {}
                TaskJoinOutcome::Failed(error) => {
                    anyhow::bail!("Lighter WebSocket handler failed: {error}");
                }
                TaskJoinOutcome::Incomplete => {
                    anyhow::bail!("Lighter WebSocket handler did not stop after abort");
                }
            }
        }

        self.signal.store(false, Ordering::Release);
        self.initial_connect_cancellation
            .store(Arc::new(cancellation_token.clone()));

        let (message_handler, raw_rx) = channel_epoch_message_handler();
        let cfg = WebSocketConfig {
            url: self.url.clone(),
            headers: vec![],
            heartbeat_interval_secs: Some(HEARTBEAT_INTERVAL.as_secs()),
            heartbeat_payload: None,
            connect_timeout_ms: Some(self.ws_timeout_secs.saturating_mul(1_000).max(1)),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the inner `{error}` in the message — it contains the root cause from the handler task; fix that underlying issue first.
  2. Verify Lighter API key, secret and account index are correct and the key is active on the exchange.
  3. Check network connectivity / proxy / firewall stability to Lighter's WebSocket endpoint; test with a simple wss client.
  4. Enable debug logging (log::debug in the handler) to see what the handler task logged before failing.
  5. Retry connect(); transient network failures resolve on reconnect, and the adapter's reconnect mechanism may also recover it.

Example fix

// before: connect with wrong credentials
let client = factory.create("ws://mainnet.zklighter.elliot.ai/stream", creds)?;
client.connect().await?; // Lighter WebSocket handler failed: auth rejected

// after: verify credentials before connecting
assert!(!creds.api_key.is_empty() && creds.account_index > 0);
let client = factory.create("wss://mainnet.zklighter.elliot.ai/stream", creds)?;
client.connect().await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: verify endpoint reachability and credentials
assert!(!creds.api_key.is_empty());
// optionally ping the stream endpoint before connect

Try / catch

match client.connect().await {
    Ok(()) => {},
    Err(e) if e.to_string().contains("handler failed") => {
        log::error!("handler error: {e:#}"); // inspect inner cause
        // retry with backoff
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling connect() (via connect_with_cancellation) when the freshly spawned WebSocket handler task returns Err before or during the join — e.g. the underlying websocket connection drops, authentication to Lighter fails inside the handler, or a stream yields an error immediately.

Common situations: Invalid API credentials passed to the Lighter credentials provider; network/proxy dropping the TCP connection right after the handshake; Lighter exchange-side rejection during subscribe/auth; an expired signing key configured in the adapter factory.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/d0317b3c52daa517. Report an issue: GitHub.