{"record":{"id":"6e1617a56492cd09","repo":"nautechsystems/nautilus_trader","slug":"timeout-after-1-s-awaiting-lighter-account-stre","errorCode":null,"errorMessage":"Timeout after {:.1}s awaiting Lighter account streams: pending={:?}","messagePattern":"Timeout after (.+?)s awaiting Lighter account streams: pending=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/lighter/src/websocket/dispatch.rs","lineNumber":757,"sourceCode":"            // `all_ready` test and the `.await` is still observed; with\n            // `notify_waiters` the registration guarantees future notifies\n            // reach us.\n            let waiter = self.notify.notified();\n            tokio::pin!(waiter);\n            waiter.as_mut().enable();\n\n            if self.all_ready() {\n                log::debug!(\n                    \"All Lighter account streams ready in {:.1}s\",\n                    start.elapsed().as_secs_f64(),\n                );\n                return Ok(());\n            }\n\n            let now = Instant::now();\n            let elapsed = now.duration_since(start);\n            if elapsed >= timeout {\n                anyhow::bail!(\n                    \"Timeout after {:.1}s awaiting Lighter account streams: pending={:?}\",\n                    timeout.as_secs_f64(),\n                    self.pending(),\n                );\n            }\n\n            // `elapsed < timeout` is established by the bail above, so the\n            // subtraction never underflows. Use `saturating_sub` anyway to\n            // satisfy `clippy::unchecked-time-subtraction`.\n            let until_timeout = timeout.saturating_sub(elapsed);\n            let until_warn = next_warn.saturating_duration_since(now);\n            let wait = until_timeout.min(until_warn);\n\n            let _ = tokio::time::timeout(wait, waiter).await;\n\n            if !self.all_ready() && Instant::now() >= next_warn {\n                log::warn!(\n                    \"Still awaiting Lighter account streams after {}s: pending={:?}\",","sourceCodeStart":739,"sourceCodeEnd":775,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/lighter/src/websocket/dispatch.rs#L739-L775","documentation":"Raised by the Lighter WebSocket dispatcher when waiting for required account streams (orders, positions, balances) to arrive does not complete within the allotted timeout. The error reports the elapsed seconds and the list of still-pending stream kinds so the developer can see which subscriptions never delivered data.","triggerScenarios":"Subscribing to account streams and awaiting their initial snapshots when one or more streams stay empty past the timeout — subscription rejected by Lighter, auth not accepted for the account, or no data ever published for the requested account.","commonSituations":"Wrong account_index configured so Lighter never pushes that account's data; API key lacking permission for private channels; network stall on private topics; exchange incident delaying snapshots.","solutions":["Read pending={:?} in the message to identify which stream(s) never arrived; investigate that specific subscription.","Verify account_index and API credentials grant access to the private (account) channels.","Increase the await timeout if the exchange is slow but reachable.","Test the same subscription manually against the Lighter stream endpoint with wscat to confirm data flows.","Check Lighter status/announcements for private-channel outages; retry with backoff."],"exampleFix":"// before: waiting for all account streams with a short timeout\nwait_for_account_streams(timeout: Duration::from_secs(5)).await?;\n\n// after: longer timeout and explicit pending diagnostics\nwait_for_account_streams(timeout: Duration::from_secs(30)).await\n    .inspect_err(|e| log::warn!(\"{e}; check subscriptions/auth\"))?;","handlingStrategy":"validation","validationCode":"// before awaiting, confirm credentials can access private channels\nassert!(creds.account_index > 0);\nassert!(!creds.api_key.is_empty());","typeGuard":null,"tryCatchPattern":"match wait_for_account_streams(timeout).await {\n    Err(e) if e.to_string().contains(\"awaiting Lighter account streams\") => {\n        log::error!(\"{e:#}\"); // parse pending={:?} to see missing streams\n        // retry or fail fast depending on which stream is pending\n    }\n    r => r?,\n}","preventionTips":["Verify account_index and API key permissions for private channels","Use a generous timeout for initial stream snapshots","Manually test subscriptions with wscat against the stream endpoint","Monitor exchange status for private-channel incidents"],"tags":["websocket","timeout","streams","rust"],"backgroundTag":"request-timeout","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}