{"record":{"id":"0e95f8be1ce6d7e3","repo":"nautechsystems/nautilus_trader","slug":"ax-open-orders-pagination-returned-duplicate-order","errorCode":null,"errorMessage":"AX open-orders pagination returned duplicate order ID {}","messagePattern":"AX open-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":2049,"sourceCode":"                next_offset <= total_count,\n                \"AX open-orders page exceeds total_count: next offset {next_offset}, total {total_count}\"\n            );\n\n            if total_count == 0 {\n                anyhow::ensure!(\n                    response.orders.is_empty(),\n                    \"AX open-orders returned rows with total_count zero\"\n                );\n                break;\n            }\n\n            anyhow::ensure!(\n                !response.orders.is_empty(),\n                \"AX open-orders returned an empty page before offset {offset} reached total {total_count}\"\n            );\n\n            for order in response.orders {\n                anyhow::ensure!(\n                    seen_order_ids.insert(order.oid.clone()),\n                    \"AX open-orders pagination returned duplicate order ID {}\",\n                    order.oid\n                );\n                orders.push(order);\n            }\n\n            if next_offset == total_count {\n                break;\n            }\n\n            offset = next_offset;\n        }\n\n        anyhow::ensure!(\n            i64::try_from(orders.len()).context(\"AX open-orders result length exceeds i64\")?\n                == expected_total.unwrap_or_default(),\n            \"AX open-orders pagination did not return the advertised number of unique orders\"","sourceCodeStart":2031,"sourceCodeEnd":2067,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/architect_ax/src/http/client.rs#L2031-L2067","documentation":"The open-orders pagination collects all order IDs in a seen-set and aborts if the same oid appears twice across pages. Duplicates would corrupt the caller's view of open orders (double-counted positions/sizes), so the client treats repetition as a contract violation.","triggerScenarios":"Server returns overlapping pages — e.g. rows inserted before the current offset during pagination, or unstable sort order shifting rows between pages.","commonSituations":"New orders inserted server-side mid-pagination shifting offsets; venue returning unsorted data that the adapter assumes is stable; API regression in page slicing.","solutions":["Restart pagination from offset 0 and complete it quickly","Request a stable sort parameter if the API supports it, so rows don't shift between pages","Increase page size to finish in one page, eliminating offset-shift risk","Report overlapping-page behavior to AX/adapter maintainers with the raw responses"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"let mut seen = std::collections::HashSet::new();\nfor o in &all_orders {\n    if !seen.insert(o.oid.clone()) {\n        return Err(anyhow!(\"duplicate order {} across pages\", o.oid));\n    }\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"duplicate order ID\") => restart_pagination_with_stable_sort(),\n    Err(e) => return Err(e),\n    Ok(orders) => use(orders),\n}","preventionTips":["Request a stable sort from the API if supported so rows don't shift between pages","Increase page size to fetch everything in one page","Avoid order inserts from other processes on the same account during pagination"],"tags":["pagination","duplicate-data","http"],"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-14T00:17:10.932Z"}