nautechsystems/nautilus_trader · error

Lighter nonce refresh is pending for connection epoch {conne

Error message

Lighter nonce refresh is pending for connection epoch {connection_epoch}

What it means

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.

Source

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

                } else {
                    log::debug!("Lighter auth-token refresh task cancelled");
                    break;
                }
            }
        })?;
        Ok(())
    }

    // Per-order `params["market_order_slippage_bps"]` overrides the config default.
    fn resolve_slippage_bps(&self, params: Option<&Params>) -> u32 {
        params
            .and_then(|p| p.get_u64("market_order_slippage_bps"))
            .map_or(self.config.market_order_slippage_bps, |v| v as u32)
    }

    fn build_tx_context(&self, credential: &Credential) -> anyhow::Result<ReservedTxContext> {
        let connection_epoch = self.ws_client.connection_epoch();
        anyhow::ensure!(
            self.nonce_ready_connection_epoch.load(Ordering::Acquire) == connection_epoch,
            "Lighter nonce refresh is pending for connection epoch {connection_epoch}",
        );
        let nonce_guard = Arc::clone(&self.nonce_submission_gate)
            .try_read_owned()
            .context("Lighter nonce refresh is in progress")?;
        anyhow::ensure!(
            self.ws_client.connection_epoch() == connection_epoch
                && self.nonce_ready_connection_epoch.load(Ordering::Acquire) == connection_epoch,
            "Lighter connection or nonce state changed during transaction preparation",
        );
        let nonce = match self
            .dispatch
            .nonce_manager
            .next_nonce(credential.account_index(), credential.api_key_index())
        {
            Ok(nonce) => nonce,
            Err(e @ NonceError::SkipWindowExhausted { .. }) => {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Wait for nonce readiness before issuing signed commands: retry after a short delay or await the adapter's ready signal.
  2. Retry the operation; the nonce refresh completes automatically shortly after connect.
  3. Check WS connectivity/logs if the condition persists — the refresh may be failing repeatedly.
  4. Serialize submit logic so commands are not queued before the connection is fully initialized.

Example fix

// before
execution.update_leverage(instrument_id, leverage)?;
// after
if !execution.is_nonce_ready() {
    tokio::time::sleep(Duration::from_millis(250)).await; // or await ready signal
}
execution.update_leverage(instrument_id, leverage)?;
Defensive patterns

Strategy: retry

Validate before calling

// Rust
if adapter.nonce_ready_epoch() != adapter.connection_epoch() {
    return Err("nonce refresh pending; retry after connect settles");
}

Try / catch

match adapter.update_leverage(id, lev) {
    Err(e) if e.to_string().contains("nonce refresh is pending") => {
        tokio::time::sleep(Duration::from_millis(200)).await;
        // retry once or twice, then surface
    }
    other => other,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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