nautechsystems/nautilus_trader · error
Order missing order_qty and cannot reconstruct (order_id={},
Error message
Order missing order_qty and cannot reconstruct (order_id={}, cum_qty={:?}, leaves_qty={:?}) What it means
parse_order_status_report reconstructs order quantities for a BitMEX order status response. When the raw order has no order_qty, it tries to reconstruct order and filled quantities from cum_qty/leaves_qty; if that reconstruction also fails (quantities incompatible with a zero-quantity fallback), it bails with this error. It means the exchange response lacks enough information to build a valid OrderStatusReport.
Source
Thrown at crates/adapters/bitmex/src/http/parse.rs:928
cum,
leaves,
);
let quantity = parse_signed_contracts_quantity(cum + leaves, instrument);
let filled_qty = parse_signed_contracts_quantity(cum, instrument);
(quantity, filled_qty)
} else if order_status == OrderStatus::Canceled || order_status == OrderStatus::Rejected {
// For canceled/rejected orders, both quantities will be reconciled from cache
// BitMEX sometimes omits all quantity fields in cancel responses
log::debug!(
"Order missing quantity fields, using 0 for both (will be reconciled from cache): order_id={:?}, client_order_id={:?}, status={:?}",
order.order_id,
order.cl_ord_id,
order_status,
);
let zero_qty = Quantity::zero(instrument.size_precision());
(zero_qty, zero_qty)
} else {
anyhow::bail!(
"Order missing order_qty and cannot reconstruct (order_id={}, cum_qty={:?}, leaves_qty={:?})",
order.order_id,
order.cum_qty,
order.leaves_qty
);
};
let report_id = UUID4::new();
let ts_accepted = order.transact_time.map_or(ts_init, UnixNanos::from);
let ts_last = order.timestamp.map_or(ts_init, UnixNanos::from);
let mut report = OrderStatusReport::new(
account_id,
instrument_id,
None, // client_order_id - will be set later if present
venue_order_id,
order_side,
order_type,
time_in_force,View on GitHub (pinned to 18893faf8b)
Solutions
- Re-query the order via query_order after a short delay so BitMEX returns a complete payload including orderQty
- Check the raw BitMEX response (orderQty, cumQty, leavesQty) to confirm which field is missing; if the order was rejected, treat it as rejected rather than reconstructing quantities
- Verify the instrument mapping (size_precision) is correct — a wrong instrument can make reconstructed quantities invalid
- Upgrade/patch the adapter to fall back to zero quantities for unfillable orders instead of erroring if your workflow tolerates it
Example fix
// before: caller assumes a report always comes back
let report = adapter.query_order(instr, client_order_id).await?;
// after: treat missing-quantity reconstruction as an unresolvable order state
match adapter.query_order(instr, client_order_id).await {
Ok(report) => handle(report),
Err(e) if e.to_string().contains("cannot reconstruct") => {
log::warn!("order {} has no reconstructable qty; polling again", client_order_id);
tokio::time::sleep(Duration::from_millis(250)).await;
handle(adapter.query_order(instr, client_order_id).await?)
}
Err(e) => return Err(e),
} Defensive patterns
Strategy: validation
Validate before calling
fn has_reconstructable_qty(order: &BitmexOrder) -> bool {
order.order_qty.is_some()
|| (order.cum_qty.is_some() && order.leaves_qty.is_some())
}
// gate the call: if !has_reconstructable_qty(&raw_order) { poll again or mark order unresolvable } Type guard
fn order_has_qty(order: &BitmexOrder) -> bool {
order.order_qty.map(|q| q > 0).unwrap_or(false)
|| matches!((order.cum_qty, order.leaves_qty), (Some(_), Some(_)))
} Try / catch
match client.query_order(instrument, cl_ord_id).await {
Ok(report) => Ok(report),
Err(e) if e.to_string().contains("cannot reconstruct") => {
warn!("no quantity in order status for {cl_ord_id}; retrying");
client.query_order(instrument, cl_ord_id).await
}
Err(e) => Err(e),
} Prevention
- Poll query_order shortly after submit/cancel so BitMEX has echoed full order data
- Log raw BitMEX order payloads to spot missing orderQty fields early
- Verify instrument size_precision mappings for every traded symbol
- Treat immediately-rejected orders as terminal instead of expecting a full status report
When it happens
Trigger: Calling submit_order, cancel_order, cancel_orders, cancel_all_orders, modify_order, or query_order when BitMEX returns an order status payload with no orderQty field and cum_qty/leaves_qty that cannot yield a valid quantity (e.g. both absent or malformed).
Common situations: Querying an order that was rejected before any quantity was recorded; BitMEX API returning partial/amended order data; orders cancelled immediately after submit so the exchange never echoed orderQty; stale or synthetic order rows in reconciliation.
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
- missing persistence type for order update {}
- Skipping non-trade execution: {:?}
- Skipping execution without side: {:?}
- Invalid scientific notation exponent '{exponent}': must be a
- {FAILED}: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/87c00c54a2e49271.
Report an issue: GitHub.