{"record":{"id":"69d3a09328052056","repo":"nautechsystems/nautilus_trader","slug":"ax-fills-pagination-returned-duplicate-trade-id","errorCode":null,"errorMessage":"AX fills pagination returned duplicate trade ID {}","messagePattern":"AX fills pagination returned duplicate trade ID (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/http/client.rs","lineNumber":2272,"sourceCode":"\n            if let Some(total_count) = response.total_count {\n                anyhow::ensure!(\n                    total_count >= 0,\n                    \"AX fills total_count must be non-negative, was {total_count}\"\n                );\n\n                if let Some(expected) = expected_total {\n                    anyhow::ensure!(\n                        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!(","sourceCodeStart":2254,"sourceCodeEnd":2290,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/architect_ax/src/http/client.rs#L2254-L2290","documentation":"Every fill accepted from a page is inserted into a seen_trade_ids HashSet; if a trade_id was already seen the request fails immediately. With sort_ts=desc, any fill that is executed (or corrected) while pagination is in progress shifts later pages and re-serves rows. The guard prevents the same execution from being counted twice in reconciliation.","triggerScenarios":"A fill executes between fetching page N and page N+1; because pages are ordered newest-first with an offset-style cursor, the new row pushes existing rows into the next page and the same trade_id appears twice. Also occurs if AX restates a fill with an unchanged trade_id.","commonSituations":"Reconciling fills on an actively trading account; long cursor chains (large 7-day windows with PAGE_SIZE 100) that raise the chance of overlap; concurrent connections mutating the same fill history.","solutions":["Retry the entire traversal when the account is quiet — duplicates from shifting pages are transient","Pass explicit start/end anchored in the past so new executions fall outside the window","Shrink the window (e.g. day-by-day slices) so each traversal is short","If it reproduces deterministically on a frozen dataset, record the raw page sequence (curl with cursor param) and report to AX — the cursor chain is serving overlapping 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(\"duplicate trade ID\") => {\n        log::warn!(\"overlapping fills pages (active trading?); retrying: {e}\");\n        tokio::time::sleep(Duration::from_secs(3)).await;\n        client.request_fill_reports(account_id, Some(start), Some(end)).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Prefer fully historical windows that cannot gain new fills mid-traversal","Defer reconciliation while strategies are submitting orders on the same account","If duplicates recur on static data, persist raw pages once and analyze the cursor chain instead of retrying blindly"],"tags":["architect-ax","fills","pagination","duplicates","race-condition"],"backgroundTag":"pagination-duplicate-records","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}