nautechsystems/nautilus_trader · error · anyhow::Error
AX final-settlement fill must also be classified as a block
Error message
AX final-settlement fill must also be classified as a block trade
What it means
parse_fill_report models final settlements as synthetic block fills (venue order id "AX-FILL-{trade_id}"), so it requires any fill with is_final_settlement = true to also carry is_block_trade = true. A fill flagged as final settlement but explicitly not a block trade is ambiguous under that model and is rejected instead of mis-linked to an order.
Source
Thrown at crates/adapters/architect_ax/src/http/parse.rs:659
/// # Errors
///
/// Returns an error if:
/// - Price or quantity fields cannot be parsed.
/// - Fee parsing fails.
/// - Fill classification is inconsistent.
/// - A fill is neither explicitly special nor linked to a valid order ID.
pub fn parse_fill_report(
fill: &AxFill,
account_id: AccountId,
instrument: &InstrumentAny,
ts_init: UnixNanos,
) -> anyhow::Result<FillReport> {
let instrument_id = instrument.id();
let trade_id = TradeId::new_checked(&fill.trade_id).context("Invalid trade_id in Ax fill")?;
let is_block_trade = fill.is_block_trade;
let is_final_settlement = fill.is_final_settlement;
anyhow::ensure!(
!(is_final_settlement == Some(true) && is_block_trade == Some(false)),
"AX final-settlement fill must also be classified as a block trade"
);
let is_special_fill = is_block_trade == Some(true) || is_final_settlement == Some(true);
let venue_order_id = if is_special_fill {
VenueOrderId::new_checked(format!("AX-FILL-{}", fill.trade_id))
.context("Invalid synthetic venue order ID for AX fill")?
} else {
let order_id = fill
.order_id
.as_deref()
.context("AX fill is missing order_id and explicit special-fill classification")?;
anyhow::ensure!(
!order_id.is_empty(),
"AX regular fill has an empty order_id"
);
VenueOrderId::new_checked(order_id).context("Invalid order_id in AX fill")?View on GitHub (pinned to a4b06ed870)
Solutions
- Fetch the raw fill by the trade_id from /fills and inspect both flags to confirm the mismatch
- If the fill really is a settlement, correct the classification upstream so is_block_trade is also true (venue config or the integration writing fills)
- If AX semantics genuinely allow settlement-without-block, relax the invariant in the adapter via a PR with tests covering both flags
- Until fixed, expect the fills request containing this fill to fail and reconcile the affected trades manually
Example fix
// before (AX fill payload)
{"trade_id": "T1", "is_final_settlement": true, "is_block_trade": false}
// after
{"trade_id": "T1", "is_final_settlement": true, "is_block_trade": true} Defensive patterns
Strategy: validation
Validate before calling
// Pre-check fill classification flags before parsing (parse_fill_report is pub)
fn fill_flags_consistent(fill: &AxFill) -> bool {
!(fill.is_final_settlement == Some(true) && fill.is_block_trade == Some(false))
}
for fill in &fills {
if !fill_flags_consistent(fill) {
log::error!("fill {} has inconsistent settlement/block flags; quarantining", fill.trade_id);
continue;
}
reports.push(parse_fill_report(fill, account_id, &instrument, ts_init)?);
} Try / catch
match parse_fill_report(fill, account_id, &instrument, ts_init) {
Ok(report) => reports.push(report),
Err(e) if e.to_string().contains("must also be classified as a block trade") => {
log::error!("quarantining fill {}: settlement/block flag mismatch: {e}", fill.trade_id);
quarantined.push(fill.trade_id.clone()); // reconcile manually, do not double-count
}
Err(e) => return Err(e),
} Prevention
- When writing fills from custom integrations, always set is_block_trade alongside is_final_settlement
- Contract-test fill classification flags after AX API upgrades
- Track quarantined fills in a dead-letter list so settlements are not silently dropped from books
When it happens
Trigger: The /fills stream returns a fill with is_final_settlement: true and is_block_trade: false — e.g. the venue starts emitting settlement fills without the block flag, or a custom integration writes fills with incomplete classification flags.
Common situations: AX changes fill classification semantics between versions; a perp contract expires and its settlement fill arrives with flags the adapter's invariant does not allow; hand-crafted fills in test fixtures with only one flag set.
Related errors
- AX regular fill has an empty order_id
- AX fills total_count must be non-negative, was {total_count}
- AX fills total_count changed during pagination: expected {ex
- AX fills pagination returned duplicate trade ID {}
- AX fills pagination returned more unique rows ({}) than tota
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/7db90ff6ec65b7aa.
Report an issue: GitHub.