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.

Solutions

  1. Restart pagination from the first page to get a clean snapshot
  2. Check that cursors are passed through unmodified (encoding/truncation by the adapter would replay pages)
  3. Increase page size to reduce the number of cursors and overlap opportunities
  4. 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

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


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

Appendix: 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(&params)
                .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)