nautechsystems/nautilus_trader · error

failed to re-subscribe Lighter account channels: {error}

Error message

failed to re-subscribe Lighter account channels: {error}

What it means

Raised by rotate_auth_token_once after the Lighter auth token rotates: the adapter re-subscribes account-scoped WebSocket channels under the new token, and if any re-subscription fails it aggregates the first channel error and aborts the rotation with this message. The WebSocket connection is left in a state where some account channels may no longer receive updates until reconnection.

Source

Thrown at crates/adapters/lighter/src/execution.rs:2407

) -> anyhow::Result<()>
where
    MintToken: FnMut(&Credential) -> anyhow::Result<SecretString>,
    Subscribe: FnMut(LighterWsChannel, SecretString) -> SubscribeFuture,
    SubscribeFuture: Future<Output = Result<(), crate::websocket::error::LighterWsError>>,
{
    let token =
        mint_token(credential).context("failed to mint Lighter auth token during rotation")?;
    let mut first_error = None;

    for channel in channels {
        if let Err(e) = subscribe(channel.clone(), token.clone()).await {
            log::debug!("Lighter auth-token rotation: re-subscribe failed for {channel:?}: {e}",);
            first_error.get_or_insert_with(|| format!("{channel:?}: {e}"));
        }
    }

    if let Some(error) = first_error {
        anyhow::bail!("failed to re-subscribe Lighter account channels: {error}");
    }

    Ok(())
}

async fn sleep_or_auth_token_refresh_cancelled(
    duration: Duration,
    cancellation_token: &CancellationToken,
) -> bool {
    tokio::select! {
        () = cancellation_token.cancelled() => false,
        () = tokio::time::sleep(duration) => true,
    }
}

fn auth_token_refresh_next_delay(outcome: AuthTokenRefreshOutcome) -> Option<Duration> {
    match outcome {
        AuthTokenRefreshOutcome::Rotated => Some(AUTH_TOKEN_REFRESH_INTERVAL),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Force a full WebSocket reconnect so all channels re-subscribe cleanly under the new token
  2. Verify the refreshed auth token is accepted by the venue (clock skew can invalidate JWTs)
  3. Check network stability; retry token rotation after the socket is reconnected
  4. Confirm venue auth-token TTL/rotation API behavior matches the adapter's expectations

Example fix

// before: treat any rotation error as fatal for the task
if let Err(e) = refresh_auth_token_until_rotated(&mut task).await { return Err(e); }
// after: reconnect WS on re-subscribe failure
if let Err(e) = refresh_auth_token_until_rotated(&mut task).await {
    if e.to_string().contains("failed to re-subscribe Lighter account channels") {
        ws.reconnect().await?; // re-subscribes all channels under the new token
    } else { return Err(e); }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before rotating, confirm the socket is healthy
if !ws.is_connected() { ws.reconnect().await?; }

Try / catch

if let Err(e) = rotation.refresh_auth_token_until_rotated().await {
    if e.to_string().contains("failed to re-subscribe Lighter account channels") {
        ws.reconnect().await?; // full resubscribe under the new token
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: An auth token refresh (via refresh_auth_token_until_rotated) succeeds but one or more WS account channel re-subscribe messages fail — connection dropped mid-rotation, server rejects the new token, or the socket write fails.

Common situations: Long-running sessions crossing the token TTL, venue-side connection resets during rotation, network instability at rotation time, or a rotated token not yet valid venue-side.

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/abbc734f4aa39645. Report an issue: GitHub.