nautechsystems/nautilus_trader · error · anyhow::Error
AX fills returned an empty next_cursor
Error message
AX fills returned an empty next_cursor
What it means
If the server supplies a next_cursor, it must be a non-empty string — an empty cursor string cannot be sent back to request the next page and indicates a malformed paging response. The client rejects it so the caller doesn't loop or fail later with a bad request.
Solutions
- Capture the raw response JSON and confirm the empty next_cursor, then retry the pagination — often transient.
- Treat the current page as final if the server keeps doing this: check whether the client and server versions agree on cursor semantics.
- Report the empty-cursor response to the AX service team with the request parameters used.
- If it coincides with an exact-multiple row count (page_len == limit), verify the server's end-of-data detection.
Defensive patterns
Strategy: try-catch
Try / catch
match client.paginate_fills(params).await {
Ok(fills) => apply(fills),
Err(e) if e.to_string().contains("empty next_cursor") => {
warn!("AX blank cursor; treating current page as final if retry fails");
client.paginate_fills(params).await.or_else(|_| fallback_partial_fetch(params))
}
Err(e) => return Err(e),
} Prevention
- Retry once before giving up; blank cursors are often transient server bugs.
- Record raw responses for bug reports to the AX team.
- Verify client/server cursor-format compatibility after upgrades.
When it happens
Trigger: A fills page response where next_cursor is Some("") — server signaled 'more pages' but produced a blank cursor value.
Common situations: Server bug when the last page is exactly one row short; middleware trimming string fields; newer server serialization change the client wasn't built for.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- AX fills returned an empty page with a next_cursor
- AX fills applied limit must be between 0 and
- AX fills page length
- AX fills pagination repeated cursor
- AX fills pagination returned duplicate trade ID
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e64b635c0e16326f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/architect_ax/src/http/client.rs:2276
anyhow::ensure!(
seen_trade_ids.insert(fill.trade_id.clone()),
"AX fills pagination returned duplicate trade ID {}",
fill.trade_id
);
fills.push(fill);
}
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 {View on GitHub (pinned to 18893faf8b)