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

  1. Re-query the order via query_order after a short delay so BitMEX returns a complete payload including orderQty
  2. 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
  3. Verify the instrument mapping (size_precision) is correct — a wrong instrument can make reconstructed quantities invalid
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/87c00c54a2e49271. Report an issue: GitHub.