{"record":{"id":"12690f6fdc63eb55","repo":"nautechsystems/nautilus_trader","slug":"ax-orders-pagination-returned-duplicate-order-id","errorCode":null,"errorMessage":"AX orders pagination returned duplicate order ID {}","messagePattern":"AX orders pagination returned duplicate order ID (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/http/client.rs","lineNumber":2140,"sourceCode":"        let mut params = GetOrdersParams {\n            start_timestamp_ns: start.map(|timestamp| timestamp.as_i64()),\n            end_timestamp_ns: end.map(|timestamp| timestamp.as_i64()),\n            limit: Some(PAGE_SIZE),\n            ..Default::default()\n        };\n        let mut orders = Vec::new();\n        let mut seen_cursors = HashSet::new();\n        let mut seen_order_ids = HashSet::new();\n\n        loop {\n            let response = self\n                .inner\n                .get_orders(&params)\n                .await\n                .map_err(|e| anyhow::anyhow!(e))?;\n\n            for order in response.orders {\n                anyhow::ensure!(\n                    seen_order_ids.insert(order.oid.clone()),\n                    \"AX orders pagination returned duplicate order ID {}\",\n                    order.oid\n                );\n                orders.push(order);\n            }\n\n            match response.next_cursor {\n                Some(next_cursor) => {\n                    anyhow::ensure!(\n                        seen_cursors.insert(next_cursor.clone()),\n                        \"AX orders pagination repeated cursor {next_cursor:?}\"\n                    );\n                    params.cursor = Some(next_cursor);\n                }\n                None => break,\n            }\n        }","sourceCodeStart":2122,"sourceCodeEnd":2158,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/architect_ax/src/http/client.rs#L2122-L2158","documentation":"Cursor-paginated AX orders fetch deduplicates order IDs across pages with a seen-set; a repeated oid means pages overlap and the caller would see the same order twice. The client aborts to protect the consumer from duplicated order data.","triggerScenarios":"The server's cursor semantics break: two different cursors return overlapping order sets, e.g. new orders inserted shifting an unstable sort between cursor snapshots.","commonSituations":"Order inserts mid-pagination reordering results; venue cursor implementation regression; adapter sending malformed cursor values the server treats as the first page.","solutions":["Restart pagination from the first page to get a clean snapshot","Check that cursors are passed through unmodified (encoding/truncation by the adapter would replay pages)","Increase page size to reduce the number of cursors and overlap opportunities","Report overlapping cursors to AX/adapter maintainers"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"let mut seen = std::collections::HashSet::new();\nfor page in pages {\n    for o in &page.orders {\n        if !seen.insert(o.oid.clone()) {\n            return Err(anyhow!(\"overlapping pages: duplicate order {}\", o.oid));\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"duplicate order ID\") => restart_cursor_pagination(),\n    Err(e) => return Err(e),\n    Ok(orders) => use(orders),\n}","preventionTips":["Pass cursor values through unmodified — check for any encoding/trimming in transport layers","Increase page size to reduce cursor count","Restart from page 1 rather than resuming after a duplicate error"],"tags":["pagination","cursor","duplicate-data"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}