{"record":{"id":"905f9a1c438a8a06","repo":"nautechsystems/nautilus_trader","slug":"ax-fills-pagination-returned-more-unique-rows","errorCode":null,"errorMessage":"AX fills pagination returned more unique rows ({}) than total_count {total_count}","messagePattern":"AX fills pagination returned more unique rows \\((.+?)\\) than total_count (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/http/client.rs","lineNumber":2281,"sourceCode":"                        total_count == expected,\n                        \"AX fills total_count changed during pagination: expected {expected}, was {total_count}\"\n                    );\n                } else {\n                    expected_total = Some(total_count);\n                }\n            }\n\n            for fill in response.fills {\n                anyhow::ensure!(\n                    seen_trade_ids.insert(fill.trade_id.clone()),\n                    \"AX fills pagination returned duplicate trade ID {}\",\n                    fill.trade_id\n                );\n                fills.push(fill);\n            }\n\n            if let Some(total_count) = expected_total {\n                anyhow::ensure!(\n                    fills.len() as i64 <= total_count,\n                    \"AX fills pagination returned more unique rows ({}) than total_count {total_count}\",\n                    fills.len()\n                );\n            }\n\n            match response.next_cursor {\n                Some(next_cursor) => {\n                    anyhow::ensure!(\n                        !next_cursor.is_empty(),\n                        \"AX fills returned an empty next_cursor\"\n                    );\n                    anyhow::ensure!(\n                        page_len > 0,\n                        \"AX fills returned an empty page with a next_cursor\"\n                    );\n                    anyhow::ensure!(\n                        seen_cursors.insert(next_cursor.clone()),","sourceCodeStart":2263,"sourceCodeEnd":2299,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/architect_ax/src/http/client.rs#L2263-L2299","documentation":"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).","triggerScenarios":"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).","commonSituations":"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).","solutions":["Retry when the account is idle — transient insert-driven growth clears itself","Use an explicitly bounded historical start/end window fixed before the call","Verify with curl that total_count for your exact start/end/sort params matches the number of rows the chain actually serves","If the mismatch is deterministic, the server count and row filters disagree — report to AX with the captured pages"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.request_fill_reports(account_id, Some(start), Some(end)).await {\n    Ok(reports) => Ok(reports),\n    Err(e) if e.to_string().contains(\"more unique rows than total_count\") => {\n        log::warn!(\"fills count invariant violated; retrying with tighter window\");\n        // fall back to day-sized slices that converge faster\n        pull_fills_day_by_day(client, account_id, start, end).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Slice large lookbacks into per-day requests so each traversal is short","Verify server total_count for your exact start/end params matches row counts during integration testing","Alert on any fills invariant error — they signal the snapshot is not atomic and reconciliation should not proceed silently"],"tags":["architect-ax","fills","pagination","consistency","data-validation"],"backgroundTag":"pagination-invariant-violation","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}