nautechsystems/nautilus_trader · error · anyhow::Error
AX orders pagination returned duplicate order ID {}
Error message
AX orders pagination returned duplicate order ID {} What it means
Cursor-paginated AX orders fetch deduplicates order IDs across pages with a seen-set; a repeated oid means pages overlap and the caller would see the same order twice. The client aborts to protect the consumer from duplicated order data.
Source
Thrown at crates/adapters/architect_ax/src/http/client.rs:2140
let mut params = GetOrdersParams {
start_timestamp_ns: start.map(|timestamp| timestamp.as_i64()),
end_timestamp_ns: end.map(|timestamp| timestamp.as_i64()),
limit: Some(PAGE_SIZE),
..Default::default()
};
let mut orders = Vec::new();
let mut seen_cursors = HashSet::new();
let mut seen_order_ids = HashSet::new();
loop {
let response = self
.inner
.get_orders(¶ms)
.await
.map_err(|e| anyhow::anyhow!(e))?;
for order in response.orders {
anyhow::ensure!(
seen_order_ids.insert(order.oid.clone()),
"AX orders pagination returned duplicate order ID {}",
order.oid
);
orders.push(order);
}
match response.next_cursor {
Some(next_cursor) => {
anyhow::ensure!(
seen_cursors.insert(next_cursor.clone()),
"AX orders pagination repeated cursor {next_cursor:?}"
);
params.cursor = Some(next_cursor);
}
None => break,
}
}View on GitHub (pinned to 18893faf8b)
Solutions
- Restart pagination from the first page to get a clean snapshot
- Check that cursors are passed through unmodified (encoding/truncation by the adapter would replay pages)
- Increase page size to reduce the number of cursors and overlap opportunities
- Report overlapping cursors to AX/adapter maintainers
Defensive patterns
Strategy: retry
Validate before calling
let mut seen = std::collections::HashSet::new();
for page in pages {
for o in &page.orders {
if !seen.insert(o.oid.clone()) {
return Err(anyhow!("overlapping pages: duplicate order {}", o.oid));
}
}
} Try / catch
match result {
Err(e) if e.to_string().contains("duplicate order ID") => restart_cursor_pagination(),
Err(e) => return Err(e),
Ok(orders) => use(orders),
} Prevention
- Pass cursor values through unmodified — check for any encoding/trimming in transport layers
- Increase page size to reduce cursor count
- Restart from page 1 rather than resuming after a duplicate error
When it happens
Trigger: The server's cursor semantics break: two different cursors return overlapping order sets, e.g. new orders inserted shifting an unstable sort between cursor snapshots.
Common situations: Order inserts mid-pagination reordering results; venue cursor implementation regression; adapter sending malformed cursor values the server treats as the first page.
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 open-orders pagination returned duplicate order ID {}
- AX orders pagination repeated cursor {next_cursor:?}
- AX fills returned an empty next_cursor
- AX fills returned an empty page with a next_cursor
- AX fills pagination repeated cursor {next_cursor:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/12690f6fdc63eb55.
Report an issue: GitHub.