nautechsystems/nautilus_trader · error · anyhow::Error
AX fills total_count must be non-negative, was {total_count}
Error message
AX fills total_count must be non-negative, was {total_count} What it means
While paginating GET /fills in request_fill_reports, the Architect HTTP client validates the server-supplied total_count on every page and requires it to be >= 0. A negative total_count means the server is reporting a corrupt or sentinel counter, so the adapter aborts the whole fills request instead of reconciling against garbage. This is a fail-fast contract guard, not a client-side data error.
Source
Thrown at crates/adapters/architect_ax/src/http/client.rs:2256
anyhow::ensure!(
page_len <= PAGE_SIZE as usize,
"AX fills page length {page_len} exceeds requested limit {PAGE_SIZE}"
);
if let Some(limit) = response.limit {
anyhow::ensure!(
(0..=PAGE_SIZE).contains(&limit),
"AX fills applied limit must be between 0 and {PAGE_SIZE}, was {limit}"
);
anyhow::ensure!(
page_len <= limit as usize,
"AX fills page length {page_len} exceeds applied limit {limit}"
);
}
if let Some(total_count) = response.total_count {
anyhow::ensure!(
total_count >= 0,
"AX fills total_count must be non-negative, was {total_count}"
);
if let Some(expected) = expected_total {
anyhow::ensure!(
total_count == expected,
"AX fills total_count changed during pagination: expected {expected}, was {total_count}"
);
} else {
expected_total = Some(total_count);
}
}
for fill in response.fills {
anyhow::ensure!(
seen_trade_ids.insert(fill.trade_id.clone()),
"AX fills pagination returned duplicate trade ID {}",View on GitHub (pinned to a4b06ed870)
Solutions
- Log or curl the raw /fills response body for the failing cursor and confirm the total_count field is actually negative
- Check the AX API changelog/docs for whether total_count can be a sentinel (e.g. -1 for unknown) in the API version you target
- If -1 is a legal 'unknown' marker, patch the response deserialization upstream of this guard (map negative to None) via a PR rather than weakening the ensure!
- Retry the request once to rule out transient payload corruption from proxies
Example fix
// before (stub /fills response)
{"fills": [...], "next_cursor": null, "total_count": -1}
// after
{"fills": [...], "next_cursor": null, "total_count": 42} Defensive patterns
Strategy: retry
Try / catch
match client.request_fill_reports(account_id, start, end).await {
Ok(reports) => { /* reconcile */ }
Err(e) if e.to_string().contains("total_count must be non-negative") => {
log::error!("AX returned negative total_count; retrying once: {e}");
// single retry with backoff; escalate if it repeats
tokio::time::sleep(Duration::from_secs(2)).await;
client.request_fill_reports(account_id, start, end).await?;
}
Err(e) => return Err(e.into()),
} Prevention
- Add a contract test that asserts the /fills schema (total_count non-negative, limit bounds, cursor shape) against the AX version you run
- Pin adapter and AX API versions together and re-run the contract test on upgrades
- Route the client through a response logger in staging so corrupt counters are visible before production reconciliation
When it happens
Trigger: A /fills page (GET with cursor, limit=100, sort_ts=desc, 7-day bounded window) returns a JSON total_count of -1 or any negative value. Typical sources: a server-side 'unknown count' sentinel, an unsigned/signed encoding bug in the AX API, a mock/test server returning defaulted i64 values, or a proxy mangling the response body.
Common situations: Pointing the client at a stub/test harness that does not implement total_count; an AX API version bump that changed total_count semantics; gateway or recording middleware that re-serializes the payload incorrectly.
Related errors
- AX fills pagination returned more unique rows ({}) than tota
- AX fills returned an empty next_cursor
- AX fills total_count changed during pagination: expected {ex
- AX fills pagination returned duplicate trade ID {}
- AX fills returned an empty page with a next_cursor
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/adc8aa59e5b324de.
Report an issue: GitHub.