nautechsystems/nautilus_trader · error · anyhow::Error
AX open-orders total_count must be non-negative, was {}
Error message
AX open-orders total_count must be non-negative, was {} What it means
A defensive invariant check on a paginated open-orders response: the venue-reported total_count must be non-negative. anyhow::ensure! aborts the open-orders aggregation loop if AX returns a negative value, which would otherwise corrupt pagination termination logic. This indicates a malformed or semantically invalid API response rather than a request failure.
Source
Thrown at crates/adapters/architect_ax/src/http/client.rs:1997
let mut offset = 0_i64;
let mut expected_total = None;
loop {
let request_offset = i32::try_from(offset)
.context("AX open-orders offset exceeds the documented int32 range")?;
let params = GetOpenOrdersParams {
account_id: None,
limit: Some(PAGE_SIZE),
offset: Some(request_offset),
sort_ts: Some("desc".to_string()),
};
let response = self
.inner
.get_open_orders_page(¶ms)
.await
.map_err(|e| anyhow::anyhow!(e))?;
anyhow::ensure!(
response.total_count >= 0,
"AX open-orders total_count must be non-negative, was {}",
response.total_count
);
anyhow::ensure!(
response.limit >= 0 && response.limit <= PAGE_SIZE,
"AX open-orders applied limit must be between 0 and {PAGE_SIZE}, was {}",
response.limit
);
anyhow::ensure!(
i64::from(response.offset) == offset,
"AX open-orders response offset mismatch: requested {offset}, was {}",
response.offset
);
let total_count = *expected_total.get_or_insert(response.total_count);
anyhow::ensure!(
response.total_count == total_count,View on GitHub (pinned to 18893faf8b)
Solutions
- Check whether the AX API version changed and update the client's response models.
- Dump the raw response body to see what was actually returned.
- Confirm the request hit the correct open-orders endpoint (not an error page deserialized as a page).
- Report the malformed response to the AX venue/adapter maintainers if the API is unchanged.
Defensive patterns
Strategy: try-catch
Validate before calling
// after receiving a page, check invariants yourself
if response.total_count < 0 {
return Err(anyhow!("malformed AX page: negative total_count {}", response.total_count));
} Try / catch
match client.request_open_orders_paged().await {
Ok(orders) => orders,
Err(e) if e.to_string().contains("total_count") => {
tracing::error!("AX returned malformed open-orders page: {e:#}");
Vec::new() // or surface a schema-drift alert
}
Err(e) => return Err(e),
}; Prevention
- Pin the AX API version the adapter was built against and verify on deploy.
- Log raw response bodies on validation failures for post-mortem.
- Alert on schema-invariant failures — they indicate venue/API drift, not transient faults.
- Use mock servers that replay real captured AX responses, not hand-made ones.
When it happens
Trigger: Calling the paginated open-orders fetch when AX returns a page whose total_count field is negative — only possible if the response schema/serialization changed or a proxy/gateway returned unexpected body content.
Common situations: AX API version change altering the response schema; a misbehaving gateway or mock server returning placeholder values; deserializing an unrelated error body into the page struct due to a wrong endpoint or content-type.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- AX open-orders applied limit must be between 0 and {PAGE_SIZ
- AX open-orders response offset mismatch: requested {offset},
- Binance user-trades pagination made no progress
- Execution payload storage is marked ready without its write
- height must be positive, was {self.height}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ba594df2266a079a.
Report an issue: GitHub.