{"record":{"id":"abbc734f4aa39645","repo":"nautechsystems/nautilus_trader","slug":"failed-to-re-subscribe-lighter-account-channels","errorCode":null,"errorMessage":"failed to re-subscribe Lighter account channels: {error}","messagePattern":"failed to re-subscribe Lighter account channels: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/lighter/src/execution.rs","lineNumber":2407,"sourceCode":") -> anyhow::Result<()>\nwhere\n    MintToken: FnMut(&Credential) -> anyhow::Result<SecretString>,\n    Subscribe: FnMut(LighterWsChannel, SecretString) -> SubscribeFuture,\n    SubscribeFuture: Future<Output = Result<(), crate::websocket::error::LighterWsError>>,\n{\n    let token =\n        mint_token(credential).context(\"failed to mint Lighter auth token during rotation\")?;\n    let mut first_error = None;\n\n    for channel in channels {\n        if let Err(e) = subscribe(channel.clone(), token.clone()).await {\n            log::debug!(\"Lighter auth-token rotation: re-subscribe failed for {channel:?}: {e}\",);\n            first_error.get_or_insert_with(|| format!(\"{channel:?}: {e}\"));\n        }\n    }\n\n    if let Some(error) = first_error {\n        anyhow::bail!(\"failed to re-subscribe Lighter account channels: {error}\");\n    }\n\n    Ok(())\n}\n\nasync fn sleep_or_auth_token_refresh_cancelled(\n    duration: Duration,\n    cancellation_token: &CancellationToken,\n) -> bool {\n    tokio::select! {\n        () = cancellation_token.cancelled() => false,\n        () = tokio::time::sleep(duration) => true,\n    }\n}\n\nfn auth_token_refresh_next_delay(outcome: AuthTokenRefreshOutcome) -> Option<Duration> {\n    match outcome {\n        AuthTokenRefreshOutcome::Rotated => Some(AUTH_TOKEN_REFRESH_INTERVAL),","sourceCodeStart":2389,"sourceCodeEnd":2425,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/lighter/src/execution.rs#L2389-L2425","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Force a full WebSocket reconnect so all channels re-subscribe cleanly under the new token","Verify the refreshed auth token is accepted by the venue (clock skew can invalidate JWTs)","Check network stability; retry token rotation after the socket is reconnected","Confirm venue auth-token TTL/rotation API behavior matches the adapter's expectations"],"exampleFix":"// before: treat any rotation error as fatal for the task\nif let Err(e) = refresh_auth_token_until_rotated(&mut task).await { return Err(e); }\n// after: reconnect WS on re-subscribe failure\nif let Err(e) = refresh_auth_token_until_rotated(&mut task).await {\n    if e.to_string().contains(\"failed to re-subscribe Lighter account channels\") {\n        ws.reconnect().await?; // re-subscribes all channels under the new token\n    } else { return Err(e); }\n}","handlingStrategy":"try-catch","validationCode":"// before rotating, confirm the socket is healthy\nif !ws.is_connected() { ws.reconnect().await?; }","typeGuard":null,"tryCatchPattern":"if let Err(e) = rotation.refresh_auth_token_until_rotated().await {\n    if e.to_string().contains(\"failed to re-subscribe Lighter account channels\") {\n        ws.reconnect().await?; // full resubscribe under the new token\n    } else { return Err(e); }\n}","preventionTips":["Reconnect the WebSocket fully whenever a re-subscribe fails instead of partial retries","Keep client clock synchronized (NTP) so rotated JWTs are valid venue-side","Avoid rotating the token during known network instability"],"tags":["websocket","authentication","resubscribe","rust","token-rotation"],"backgroundTag":"connection-refused","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}