nautechsystems/nautilus_trader · error · anyhow::Error
AX fills pagination repeated cursor
Error message
AX fills pagination repeated cursor {next_cursor:?} What it means
The paginator records every next_cursor it receives; if the server ever returns a cursor it already returned, pagination would cycle forever over the same rows. The client detects the repeat and aborts, both preventing an infinite loop and surfacing the server-side cursor bug.
Solutions
- Retry the pagination once; transient stalls may not recur.
- Check that fills have a unique, stable ordering key; report non-advancing cursors to the AX backend team with the repeated cursor value logged.
- Bound the loop client-side anyway (max pages) as a defensive habit, even though this check aborts cycles.
- Pin requests to one replica/endpoint to rule out divergent cursor state.
Example fix
// before: unbounded loop trusting the server to terminate
loop { let page = client.fills(¶ms).await?; /* ... */ }
// after: bound the iterations defensively
for _ in 0..MAX_PAGES { let page = client.fills(¶ms).await?; /* ... */ } Defensive patterns
Strategy: try-catch
Try / catch
match client.paginate_fills(params).await {
Ok(fills) => apply(fills),
Err(e) if e.to_string().contains("repeated cursor") => {
error!("AX cursor stalled; aborting this sync cycle and alerting");
Err(e)
}
Err(e) => return Err(e),
} Prevention
- Bound pagination loops externally even though the client detects cycles.
- Ensure fills have stable unique ordering server-side.
- Pin reads to one replica to avoid divergent cursor state.
When it happens
Trigger: During fills pagination, a later page's next_cursor equals a cursor already used in an earlier request — the server failed to advance its cursor.
Common situations: Cursor computed from an unstable sort key (e.g. non-unique timestamp) causing the server to stall at the same position; backend deploy changed cursor encoding; load-balanced replicas returning divergent cursors.
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
- AX fills returned an empty next_cursor
- AX fills returned an empty page with a next_cursor
- AX orders pagination repeated cursor
- AX fills applied limit must be between 0 and
- AX fills page length
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d4e2f6fe4dcc25b0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/architect_ax/src/http/client.rs:2284
if let Some(total_count) = expected_total {
anyhow::ensure!(
fills.len() as i64 <= total_count,
"AX fills pagination returned more unique rows ({}) than total_count {total_count}",
fills.len()
);
}
match response.next_cursor {
Some(next_cursor) => {
anyhow::ensure!(
!next_cursor.is_empty(),
"AX fills returned an empty next_cursor"
);
anyhow::ensure!(
page_len > 0,
"AX fills returned an empty page with a next_cursor"
);
anyhow::ensure!(
seen_cursors.insert(next_cursor.clone()),
"AX fills pagination repeated cursor {next_cursor:?}"
);
params.cursor = Some(next_cursor);
}
None => break,
}
}
if let Some(total_count) = expected_total {
anyhow::ensure!(
fills.len() as i64 == total_count,
"AX fills pagination returned {} unique rows, expected {total_count}",
fills.len()
);
}
let ts_init = self.generate_ts_init();View on GitHub (pinned to 18893faf8b)