nautechsystems/nautilus_trader · error · anyhow::Error

failed to resolve positive quantity for stream order update

Error message

failed to resolve positive quantity for stream order update {} (order_type={:?}, persistence_type={:?}, size={}, bsp_liability={:?}, size_matched={:?}, size_remaining={:?}, size_cancelled={:?}, size_lapsed={:?}, size_voided={:?})

What it means

Stream-path counterpart of the OCM quantity check: while converting a stream OrderChangeMessage into report data, stream_order_quantity found size (s), bsp liability (bsp), and matched/remaining/cancelled/lapsed/voided (sm/sr/sc/sl/sv) all zero or absent, so the parser refuses to build a report. The error carries the update id and every raw size field for diagnosis.

Source

Thrown at crates/adapters/betfair/src/stream/parse.rs:829

    let size_matched = uo.sm.unwrap_or(Decimal::ZERO);
    let size_cancelled = uo.sc.unwrap_or(Decimal::ZERO);
    let size_lapsed = uo.sl.unwrap_or(Decimal::ZERO);
    let size_voided = uo.sv.unwrap_or(Decimal::ZERO);

    // Include lapsed/voided in the closed quantity for status resolution
    let size_closed = size_cancelled + size_lapsed + size_voided;
    let order_status = if uo.status == StreamingOrderStatus::ExecutionComplete
        && size_voided > Decimal::ZERO
        && size_cancelled.is_zero()
        && size_lapsed.is_zero()
    {
        OrderStatus::Voided
    } else {
        resolve_streaming_order_status(uo.status, size_matched, size_closed)
    };

    let quantity_decimal = stream_order_quantity(uo);
    anyhow::ensure!(
        quantity_decimal > Decimal::ZERO,
        "failed to resolve positive quantity for stream order update {} \
         (order_type={:?}, persistence_type={:?}, size={}, bsp_liability={:?}, \
         size_matched={:?}, size_remaining={:?}, size_cancelled={:?}, size_lapsed={:?}, size_voided={:?})",
        uo.id,
        uo.ot,
        uo.pt,
        uo.s,
        uo.bsp,
        uo.sm,
        uo.sr,
        uo.sc,
        uo.sl,
        uo.sv,
    );
    let quantity = parse_betfair_quantity(quantity_decimal)?;
    let filled_qty = parse_betfair_quantity(size_matched)?;

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Correlate the logged uo.id with listCurrentOrders output to see the venue's record for that bet.
  2. Capture the raw OCM message and file an adapter issue so the shape can be handled.
  3. If isolated to specific markets/bets, exclude them from the order stream subscription as a workaround.
Defensive patterns

Strategy: try-catch

Try / catch

for uo in &order_changes {
    match parse_stream_order_update(uo, account_id, currency, ts_init) {
        Ok(report) => reports.push(report),
        Err(e) => {
            // log the update id and continue so one bad OCM message does not kill the stream handler
            log::warn!("skipping unparseable stream order update: {e}");
        }
    }
}

Prevention

When it happens

Trigger: An order stream (OCM) update whose every quantity field is zero/None — e.g. a voided BSP bet at market closure, or venue data anomalies where size fields are omitted.

Common situations: Accounts subscribed to order streams with BSP bets that got voided; API changes omitting size fields for certain order classes.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/fa675b3f34250a15. Report an issue: GitHub.