nautechsystems/nautilus_trader · error

Lighter fill reconciliation repeated cursor `{next}`

Error message

Lighter fill reconciliation repeated cursor `{next}`

What it means

During paginated fill reconciliation, each returned next_cursor is inserted into a `seen_cursors` set. If the exchange returns a cursor that was already served, pagination would loop forever, so the adapter fails fast with this error. It detects a server-side cursor cycle.

Source

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

                .filter_map(|trade| u64::try_from(trade.timestamp).ok())
                .map(|timestamp_ms| UnixNanos::from(timestamp_ms.saturating_mul(1_000_000)))
                .min();

            if let Some(page_oldest) = page_oldest {
                oldest_served = Some(oldest_served.map_or(page_oldest, |ts| ts.min(page_oldest)));
            }

            let reached_start_boundary = cmd
                .start
                .is_some_and(|start| page_oldest.is_some_and(|oldest| oldest < start));

            if reached_start_boundary {
                break;
            }

            match response.next_cursor {
                Some(next) if !next.is_empty() => {
                    anyhow::ensure!(
                        seen_cursors.insert(next.clone()),
                        "Lighter fill reconciliation repeated cursor `{next}`",
                    );
                    cursor = Some(next);
                }
                _ => {
                    // The venue retains a bounded number of recent trades per account,
                    // so an exhausted cursor ends the retained history rather than the
                    // account's. Only a trade older than `start` proves the requested
                    // window was served in full; an account-wide sweep that served
                    // nothing has no history to retain.
                    if let (Some(start), Some(oldest)) = (cmd.start, oldest_served) {
                        covers_window = false;

                        log::warn!(
                            "Lighter fill reports do not cover {} to {}: trade pagination exhausted before the requested start; the venue `export` endpoint serves full history",
                            unix_nanos_to_iso8601(start),
                            unix_nanos_to_iso8601(oldest),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry the reconciliation after a short delay; cursor cycles are usually transient.
  2. Check Lighter status/announcements for known API pagination issues.
  3. Narrow the reconciliation window to reduce reliance on deep pagination.
  4. If persistent, capture the repeated cursor value and report it to Lighter support.
Defensive patterns

Strategy: retry

Try / catch

match res {
    Err(e) if e.to_string().contains("repeated cursor") => {
        tokio::time::sleep(BACKOFF).await;
        retry_reconciliation();
    }
    other => other,
}

Prevention

When it happens

Trigger: Lighter trades endpoint returning a repeated next_cursor during paginated fill reconciliation — typically an exchange-side anomaly or API bug, not a client config problem.

Common situations: Lighter API incidents where cursor pagination degenerates into a cycle; transient backend issues during heavy load.

Related errors


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