nautechsystems/nautilus_trader · error · anyhow::Error

AX open-orders returned rows with total_count zero

Error message

AX open-orders returned rows with total_count zero

What it means

When the venue advertises total_count of 0, the client requires the page to contain zero rows. Receiving rows alongside total_count=0 means the server's total is wrong, so the client refuses the response instead of trusting inconsistent metadata.

Source

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

            );

            let page_len = i64::try_from(response.orders.len())
                .context("AX open-orders page length exceeds i64")?;
            anyhow::ensure!(
                page_len <= i64::from(response.limit),
                "AX open-orders page length {page_len} exceeds applied limit {}",
                response.limit
            );
            let next_offset = offset
                .checked_add(page_len)
                .context("AX open-orders offset overflow")?;
            anyhow::ensure!(
                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);

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry the request after a short delay so server-side counts catch up
  2. Confirm the query filters sent match the API's documented semantics
  3. Capture the raw response and report the inconsistent total to the venue
  4. Trust rows over totals defensively only if you control the adapter fork
Defensive patterns

Strategy: retry

Validate before calling

if page.total_count == 0 && !page.orders.is_empty() {
    // inconsistent; wait and refetch
    std::thread::sleep(Duration::from_millis(200));
    return fetch_open_orders();
}

Type guard

fn is_consistent(total: i64, rows: usize) -> bool {
    total > 0 || rows == 0
}

Try / catch

match result {
    Err(e) if e.to_string().contains("rows with total_count zero") => {
        tokio::time::sleep(Duration::from_millis(250)).await;
        retry_fetch()
    }
    other => other,
}

Prevention

When it happens

Trigger: The first open-orders page returns orders but reports total_count=0 — the server's count field disagrees with its payload.

Common situations: Newly placed orders not yet reflected in the venue's count; AX API bug or caching layer returning stale totals; adapter sending filters the server counts differently than it filters rows.

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/2822aed28ee27999. Report an issue: GitHub.