{"record":{"id":"a18d1bca7f8c5ce9","repo":"nautechsystems/nautilus_trader","slug":"ax-orders-pagination-repeated-cursor-next-cursor","errorCode":null,"errorMessage":"AX orders pagination repeated cursor {next_cursor:?}","messagePattern":"AX orders pagination repeated cursor (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/http/client.rs","lineNumber":2150,"sourceCode":"        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        }\n\n        let ts_init = self.generate_ts_init();\n        let mut reports = Vec::with_capacity(orders.len());\n\n        for order in &orders {\n            let instrument = self.resolve_report_instrument(order.s).await?;\n\n            match parse_order_detail_status_report(\n                order,\n                account_id,","sourceCodeStart":2132,"sourceCodeEnd":2168,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/architect_ax/src/http/client.rs#L2132-L2168","documentation":"Cursor pagination must always move forward; the client records every next_cursor and aborts if the server hands back a cursor it already served. A repeated cursor would loop forever fetching the same page, so the guard converts an infinite loop into a clear error.","triggerScenarios":"Server returns a next_cursor identical to one previously returned, meaning it cannot advance past the current page — typically a server-side pagination bug or a corrupted/replayed cursor value.","commonSituations":"AX API pagination regression; cursor serialization issues in a proxy; adapter mutating the cursor string before sending it back.","solutions":["Verify the adapter sends the cursor value unchanged (check for encoding/trimming bugs)","Restart pagination from the beginning","Increase page size to reduce reliance on cursor chaining","Capture request/response pairs and report the stuck cursor to AX maintainers"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"let mut seen_cursors = std::collections::HashSet::new();\nif !seen_cursors.insert(next_cursor.clone()) {\n    return Err(anyhow!(\"cursor loop detected: {next_cursor:?}\"));\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"repeated cursor\") => {\n        warn!(\"AX cursor stuck; restarting pagination\");\n        restart_cursor_pagination()\n    }\n    other => other,\n}","preventionTips":["Verify cursor strings are transmitted byte-for-byte (URL-encoding issues cause replays)","Keep a page-count cap so even a stuck cursor terminates quickly","Increase page size to reduce cursor chaining"],"tags":["pagination","cursor","infinite-loop"],"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"}