{"record":{"id":"ba6a04a060e5edc6","repo":"nautechsystems/nautilus_trader","slug":"lighter-nonce-refresh-is-pending-for-connection-ep","errorCode":null,"errorMessage":"Lighter nonce refresh is pending for connection epoch {connection_epoch}","messagePattern":"Lighter nonce refresh is pending for connection epoch (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/lighter/src/execution.rs","lineNumber":1463,"sourceCode":"                } else {\n                    log::debug!(\"Lighter auth-token refresh task cancelled\");\n                    break;\n                }\n            }\n        })?;\n        Ok(())\n    }\n\n    // Per-order `params[\"market_order_slippage_bps\"]` overrides the config default.\n    fn resolve_slippage_bps(&self, params: Option<&Params>) -> u32 {\n        params\n            .and_then(|p| p.get_u64(\"market_order_slippage_bps\"))\n            .map_or(self.config.market_order_slippage_bps, |v| v as u32)\n    }\n\n    fn build_tx_context(&self, credential: &Credential) -> anyhow::Result<ReservedTxContext> {\n        let connection_epoch = self.ws_client.connection_epoch();\n        anyhow::ensure!(\n            self.nonce_ready_connection_epoch.load(Ordering::Acquire) == connection_epoch,\n            \"Lighter nonce refresh is pending for connection epoch {connection_epoch}\",\n        );\n        let nonce_guard = Arc::clone(&self.nonce_submission_gate)\n            .try_read_owned()\n            .context(\"Lighter nonce refresh is in progress\")?;\n        anyhow::ensure!(\n            self.ws_client.connection_epoch() == connection_epoch\n                && self.nonce_ready_connection_epoch.load(Ordering::Acquire) == connection_epoch,\n            \"Lighter connection or nonce state changed during transaction preparation\",\n        );\n        let nonce = match self\n            .dispatch\n            .nonce_manager\n            .next_nonce(credential.account_index(), credential.api_key_index())\n        {\n            Ok(nonce) => nonce,\n            Err(e @ NonceError::SkipWindowExhausted { .. }) => {","sourceCodeStart":1445,"sourceCodeEnd":1481,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/lighter/src/execution.rs#L1445-L1481","documentation":"build_tx_context refuses to prepare a transaction because the nonce-manager has not (re)initialized for the current WebSocket connection epoch. After a Lighter WS reconnect, nonces must be re-synced before any signed tx is built, so all tx preparation is gated on that readiness. This is a deliberate ordering guard, not corruption.","triggerScenarios":"Any call path that reaches build_tx_context — update_leverage, prepare_signed_modify_order, prepare_integrator_auto_approval — while nonce_ready_connection_epoch still holds an older epoch than ws_client.connection_epoch(), i.e. right after (re)connect before the nonce refresh task completes.","commonSituations":"Submitting modify-order or leverage updates immediately after a WS disconnect/reconnect or adapter startup; flaky network causing rapid reconnects; calling account-management endpoints before the gateway signals readiness.","solutions":["Wait for nonce readiness before issuing signed commands: retry after a short delay or await the adapter's ready signal.","Retry the operation; the nonce refresh completes automatically shortly after connect.","Check WS connectivity/logs if the condition persists — the refresh may be failing repeatedly.","Serialize submit logic so commands are not queued before the connection is fully initialized."],"exampleFix":"// before\nexecution.update_leverage(instrument_id, leverage)?;\n// after\nif !execution.is_nonce_ready() {\n    tokio::time::sleep(Duration::from_millis(250)).await; // or await ready signal\n}\nexecution.update_leverage(instrument_id, leverage)?;","handlingStrategy":"retry","validationCode":"// Rust\nif adapter.nonce_ready_epoch() != adapter.connection_epoch() {\n    return Err(\"nonce refresh pending; retry after connect settles\");\n}","typeGuard":null,"tryCatchPattern":"match adapter.update_leverage(id, lev) {\n    Err(e) if e.to_string().contains(\"nonce refresh is pending\") => {\n        tokio::time::sleep(Duration::from_millis(200)).await;\n        // retry once or twice, then surface\n    }\n    other => other,\n}","preventionTips":["Gate all signed commands on the adapter's connection/nonce-ready signal","Add reconnect-aware dispatch that queues commands until readiness","Monitor WS reconnect frequency in production"],"tags":["network","nonce","connection-state","race-condition"],"backgroundTag":"invalid-state-transition","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"}