nautechsystems/nautilus_trader · error · anyhow::Error

AX open-orders pagination returned duplicate order ID {}

Error message

AX open-orders pagination returned duplicate order ID {}

What it means

The open-orders pagination collects all order IDs in a seen-set and aborts if the same oid appears twice across pages. Duplicates would corrupt the caller's view of open orders (double-counted positions/sizes), so the client treats repetition as a contract violation.

Source

Thrown at crates/adapters/architect_ax/src/http/client.rs:2049

                next_offset <= total_count,
                "AX open-orders page exceeds total_count: next offset {next_offset}, total {total_count}"
            );

            if total_count == 0 {
                anyhow::ensure!(
                    response.orders.is_empty(),
                    "AX open-orders returned rows with total_count zero"
                );
                break;
            }

            anyhow::ensure!(
                !response.orders.is_empty(),
                "AX open-orders returned an empty page before offset {offset} reached total {total_count}"
            );

            for order in response.orders {
                anyhow::ensure!(
                    seen_order_ids.insert(order.oid.clone()),
                    "AX open-orders pagination returned duplicate order ID {}",
                    order.oid
                );
                orders.push(order);
            }

            if next_offset == total_count {
                break;
            }

            offset = next_offset;
        }

        anyhow::ensure!(
            i64::try_from(orders.len()).context("AX open-orders result length exceeds i64")?
                == expected_total.unwrap_or_default(),
            "AX open-orders pagination did not return the advertised number of unique orders"

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Restart pagination from offset 0 and complete it quickly
  2. Request a stable sort parameter if the API supports it, so rows don't shift between pages
  3. Increase page size to finish in one page, eliminating offset-shift risk
  4. Report overlapping-page behavior to AX/adapter maintainers with the raw responses
Defensive patterns

Strategy: retry

Validate before calling

let mut seen = std::collections::HashSet::new();
for o in &all_orders {
    if !seen.insert(o.oid.clone()) {
        return Err(anyhow!("duplicate order {} across pages", o.oid));
    }
}

Try / catch

match result {
    Err(e) if e.to_string().contains("duplicate order ID") => restart_pagination_with_stable_sort(),
    Err(e) => return Err(e),
    Ok(orders) => use(orders),
}

Prevention

When it happens

Trigger: Server returns overlapping pages — e.g. rows inserted before the current offset during pagination, or unstable sort order shifting rows between pages.

Common situations: New orders inserted server-side mid-pagination shifting offsets; venue returning unsorted data that the adapter assumes is stable; API regression in page slicing.

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/0e95f8be1ce6d7e3. Report an issue: GitHub.