nautechsystems/nautilus_trader · error · anyhow::Error

AX fills pagination returned more unique rows

Error message

AX fills pagination returned more unique rows ({}) than total_count {total_count}

What it means

Once pagination finishes (or per-page when total_count is known), the client asserts it never collected more unique fills than the server's total_count. Exceeding the declared total means the server's count is wrong or rows were double-counted, so the result cannot be trusted and the fetch aborts.

Solutions

  1. Retry pagination with a bounded time window so the server's count matches the rows it serves.
  2. Verify server-side how total_count is computed (snapshot vs live counter) and report the mismatch if it lags inserts.
  3. Pin reads to a single replica/consistent snapshot if the AX deployment supports it.
Defensive patterns

Strategy: retry

Try / catch

match client.paginate_fills(params).await {
    Ok(fills) => apply(fills),
    Err(e) if e.to_string().contains("more unique rows") => {
        warn!("total_count lagged inserts; retrying pagination");
        client.paginate_fills(params).await
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Accumulated unique fills.len() > total_count reported by the server — e.g. total_count stale/undercounted while rows keep arriving across pages.

Common situations: Server total_count computed before new fills were inserted; count computed per-replica while reads round-robin across replicas; fills deleted and re-added during pagination shifting IDs.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at crates/adapters/architect_ax/src/http/client.rs:2267

                        total_count == expected,
                        "AX fills total_count changed during pagination: expected {expected}, was {total_count}"
                    );
                } else {
                    expected_total = Some(total_count);
                }
            }

            for fill in response.fills {
                anyhow::ensure!(
                    seen_trade_ids.insert(fill.trade_id.clone()),
                    "AX fills pagination returned duplicate trade ID {}",
                    fill.trade_id
                );
                fills.push(fill);
            }

            if let Some(total_count) = expected_total {
                anyhow::ensure!(
                    fills.len() as i64 <= total_count,
                    "AX fills pagination returned more unique rows ({}) than total_count {total_count}",
                    fills.len()
                );
            }

            match response.next_cursor {
                Some(next_cursor) => {
                    anyhow::ensure!(
                        !next_cursor.is_empty(),
                        "AX fills returned an empty next_cursor"
                    );
                    anyhow::ensure!(
                        page_len > 0,
                        "AX fills returned an empty page with a next_cursor"
                    );
                    anyhow::ensure!(
                        seen_cursors.insert(next_cursor.clone()),

View on GitHub (pinned to 18893faf8b)