{"record":{"id":"4ea319c15ee24666","repo":"nautechsystems/nautilus_trader","slug":"binance-user-trades-pagination-made-no-progress","errorCode":null,"errorMessage":"Binance user-trades pagination made no progress","messagePattern":"Binance user-trades pagination made no progress","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/futures/execution.rs","lineNumber":2514,"sourceCode":"\n                    let page_len = page.len();\n                    let max_trade_id = page.iter().map(|trade| trade.id).max().unwrap();\n                    let passed_window_end = page.iter().any(|trade| trade.time > window_end);\n\n                    trades.extend(page.into_iter().filter(|trade| {\n                        trade.time >= window_start\n                            && trade.time <= window_end\n                            && seen_trade_ids.insert(trade.id)\n                    }));\n\n                    if page_len < USER_TRADES_PAGE_LIMIT as usize || passed_window_end {\n                        break;\n                    }\n\n                    let next_from_id = max_trade_id\n                        .checked_add(1)\n                        .context(\"Binance user trade ID overflow during pagination\")?;\n                    anyhow::ensure!(\n                        from_id.is_none_or(|cursor| next_from_id > cursor),\n                        \"Binance user-trades pagination made no progress\"\n                    );\n                    from_id = Some(next_from_id);\n                }\n\n                if window_end >= query_end_time {\n                    break;\n                }\n                window_start = window_end.saturating_add(1);\n            }\n        } else {\n            anyhow::ensure!(\n                cmd.end.is_none(),\n                \"Binance Futures fill report end time requires start time for a complete range\"\n            );\n            let mut from_id = 0;\n","sourceCodeStart":2496,"sourceCodeEnd":2532,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/binance/src/futures/execution.rs#L2496-L2532","documentation":"During time-windowed pagination of Binance user trades, the adapter advances a `from_id` cursor after each full page. Before advancing it asserts that the new cursor is strictly greater than the previous one; if the exchange keeps returning the same trade IDs the loop would spin forever, so it aborts with this error. It is an internal progress invariant guarding an API that is misbehaving or returning stale data.","triggerScenarios":"Calling generate_fill_reports (via generate_mass_status) where a full page (USER_TRADES_PAGE_LIMIT) of trades is returned whose maximum trade id plus one equals or is lower than the current from_id cursor — i.e. Binance returned overlapping/duplicate pages for the same cursor.","commonSituations":"Binance API anomalies such as cached or replayed responses behind a proxy, a mock/stub HTTP client returning the same fixture page regardless of from_id, or exchange-side ordering glitches during high trade volume.","solutions":["Retry the query after a short delay; a transient exchange-side glitch usually resolves itself.","Verify the HTTP client (or test stub) actually forwards from_id to Binance rather than returning a cached page.","Check for a proxy/CDN caching layer on api.binance.com responses and disable caching.","Upgrade the nautilus_binance adapter, in case the pagination logic has been fixed."],"exampleFix":"// before\nlet page = cached_client.query_user_trades(&params).await?;\n// after\nlet page = self.http_client.query_user_trades(&params).await?; // bypass cache, pass from_id through","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Rust\nmatch client.generate_mass_status().await {\n    Err(e) if e.to_string().contains(\"pagination made no progress\") => {\n        warn!(\"transient Binance pagination glitch, retrying\");\n        tokio::time::sleep(Duration::from_secs(2)).await;\n        client.generate_mass_status().await?;\n    }\n    r => r?,\n}","preventionTips":["Do not put caching proxies in front of Binance REST endpoints.","Use the real HTTP client (not a static stub) in tests for reconciliation paths.","Keep the adapter updated for pagination fixes."],"tags":["pagination","binance","invariant","rest-api"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}