nautechsystems/nautilus_trader · error

Binance Spot account-trades pagination made no progress

Error message

Binance Spot account-trades pagination made no progress

What it means

Safety check in the by-trade-ID pagination loop of `generate_fill_reports`: the next `fromId` cursor (max trade ID + 1) failed to strictly advance past the current cursor, meaning the loop would fetch the same page forever. Thrown to prevent an infinite loop when Binance keeps returning trades with IDs <= fromId.

Solutions

  1. Break out of pagination when the returned page contains no trades with id >= fromId (verify break conditions above).
  2. Add a page-count cap to pagination loops as a defensive limit.
  3. Report/retry later if the exchange returns inconsistent trade IDs.
  4. Check that max_trade_id is taken from the correct response field (not request echo).
Defensive patterns

Strategy: retry

Try / catch

match client.generate_mass_status(cmd).await {
    Err(e) if e.to_string().contains("pagination made no progress") => /* back off and retry once, else degrade gracefully */,
    other => other?,
}

Prevention

When it happens

Trigger: Binance's myTrades endpoint repeatedly returns a max tradeId that does not exceed the current fromId cursor (e.g. server-side data inconsistency or a stable last page that isn't recognized).

Common situations: Paging a symbol's trade history where the exchange returns a duplicated final page; race where new trades keep refreshing the last page; exchange API anomalies.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/ec62e480f188d8f8. Report an issue: GitHub.

Appendix: source

Thrown at crates/adapters/binance/src/spot/execution.rs:1398

                    page.iter().any(|report| report_time_ms(report) > end_time)
                });

                reports.extend(page.into_iter().filter(|report| {
                    requested_start_time
                        .is_none_or(|start_time| report_time_ms(report) >= start_time)
                        && requested_end_time
                            .is_none_or(|end_time| report_time_ms(report) <= end_time)
                        && seen_trade_ids.insert(report.trade_id)
                }));

                if page_len < ACCOUNT_TRADES_PAGE_LIMIT as usize || passed_end {
                    break;
                }

                let next_from_id = max_trade_id
                    .checked_add(1)
                    .context("Binance Spot trade ID overflow during pagination")?;
                anyhow::ensure!(
                    next_from_id > from_id,
                    "Binance Spot account-trades pagination made no progress"
                );
                from_id = next_from_id;
            }
        } else if let Some(query_start_time) = requested_start_time {
            let query_end_time = requested_end_time.unwrap_or_else(|| {
                self.clock.get_time_ns().as_i64() / NANOSECONDS_IN_MILLISECOND as i64
            });
            anyhow::ensure!(
                query_start_time <= query_end_time,
                "fill report start time must not exceed end time"
            );
            let mut window_start = query_start_time;

            loop {
                let window_end = window_start
                    .saturating_add(ACCOUNT_TRADES_MAX_INTERVAL_MS)

View on GitHub (pinned to 18893faf8b)