nautechsystems/nautilus_trader · error · anyhow::Error

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

Error message

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

What it means

After each page the client asserts that the count of unique fills collected so far does not exceed the total_count pinned from the first page. Collecting more unique rows than the server says exist proves the page set and the counter are inconsistent, so the request aborts. It is the running form of the total-consistency checks (errors 81 and 87).

Source

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

                        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 a4b06ed870)

Solutions

  1. Retry when the account is idle — transient insert-driven growth clears itself
  2. Use an explicitly bounded historical start/end window fixed before the call
  3. Verify with curl that total_count for your exact start/end/sort params matches the number of rows the chain actually serves
  4. If the mismatch is deterministic, the server count and row filters disagree — report to AX with the captured pages
Defensive patterns

Strategy: retry

Try / catch

match client.request_fill_reports(account_id, Some(start), Some(end)).await {
    Ok(reports) => Ok(reports),
    Err(e) if e.to_string().contains("more unique rows than total_count") => {
        log::warn!("fills count invariant violated; retrying with tighter window");
        // fall back to day-sized slices that converge faster
        pull_fills_day_by_day(client, account_id, start, end).await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: New unique fills arrive mid-traversal (sort desc pushes them into pages) while total_count stays pinned at the first page's value; or AX pages include rows outside the counted set (window semantics differ between count and rows).

Common situations: Fills reconciliation running against a live, trading account; total_count computed against a different filter than the paged rows (e.g. server counts all account fills while rows respect the start/end window).

Related errors


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