nautechsystems/nautilus_trader · error · anyhow::Error

fill quantity overflow while aggregating fill group

Error message

fill quantity overflow while aggregating fill group

What it means

This error is thrown by the live execution manager when aggregating a group of fills for an order: while summing each fill's `last_qty` as a `Decimal`, a `checked_add` overflowed. NautilusTrader uses checked arithmetic for all discrete quantity/money values and refuses to silently wrap, so the fold aborts with this error instead of producing a wrong aggregate quantity. It indicates fill quantities beyond the Decimal capacity or corrupted fill data.

Source

Thrown at crates/live/src/execution/manager.rs:1311

                "order side differs across fill group"
            );
            anyhow::ensure!(
                fill.venue_position_id == first.venue_position_id,
                "venue position ID differs across fill group"
            );
        }

        anyhow::ensure!(
            first.instrument_id == instrument.id(),
            "instrument metadata does not match fill group"
        );

        let (quantity, notional) = fills.iter().try_fold(
            (Decimal::ZERO, Decimal::ZERO),
            |(quantity, notional), fill| {
                let fill_quantity = fill.last_qty.as_decimal();
                let quantity = quantity.checked_add(fill_quantity).ok_or_else(|| {
                    anyhow::anyhow!("fill quantity overflow while aggregating fill group")
                })?;

                let fill_notional = fill_quantity
                    .checked_mul(fill.last_px.as_decimal())
                    .ok_or_else(|| {
                        anyhow::anyhow!("fill notional overflow while aggregating fill group")
                    })?;

                let notional = notional.checked_add(fill_notional).ok_or_else(|| {
                    anyhow::anyhow!("fill notional overflow while aggregating fill group")
                })?;

                Ok::<_, anyhow::Error>((quantity, notional))
            },
        )?;

        anyhow::ensure!(
            quantity > Decimal::ZERO,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the fills in the group and log each `fill.last_qty` to find the offending oversized or malformed value
  2. Verify the instrument definition (size_precision, size_increment) matches the venue's actual quantity scaling; fix adapter conversion code if quantities are not being scaled correctly
  3. Check for a bug where the same fills are aggregated more than once (double-counting inflates the running sum)
  4. Reduce order/position sizes or split the fill group if genuinely trading quantities near Decimal::MAX
  5. Report the issue with the raw venue fill payloads if values look legitimate — the Decimal bounds should never be reachable in normal trading

Example fix

// before: adapter sends raw integer size without scaling
let qty = Quantity::new(raw_size as f64, 0);
// after: scale by instrument size precision
let qty = Quantity::from_raw(raw_int, instrument.size_precision());
Defensive patterns

Strategy: validation

Validate before calling

fn fills_aggregate_within_bounds(fills: &[Fill]) -> bool {
    let mut total = Decimal::ZERO;
    for f in fills {
        match total.checked_add(f.last_qty.as_decimal()) {
            Some(t) => total = t,
            None => return false,
        }
    }
    true
}

Type guard

fn has_valid_fill_quantities(fills: &[Fill]) -> bool {
    !fills.is_empty()
        && fills.iter().all(|f| f.last_qty.as_decimal() > Decimal::ZERO)
}

Try / catch

match manager.aggregate_fill_group(&fills) {
    Ok(result) => handle(result),
    Err(e) if e.to_string().contains("fill quantity overflow") => {
        log::error!("oversized/corrupt fill quantities: {e}");
        halt_and_reconcile();
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the fill-group aggregation path (order filled events processed by the live ExecutionManager) with fills whose cumulative `last_qty` exceeds the maximum value representable by the internal fixed-precision Decimal. E.g. extremely large order sizes from a misconfigured instrument, fills with garbage/huge `last_qty` values from a venue adapter bug, or repeated aggregation of fills into an already-large accumulator.

Common situations: Exchange adapter returning wrongly scaled quantities (e.g. raw integer size instead of decimal size), an instrument definition whose size_precision mismatch causes giant decimals, historical fill replay with corrupted data, or aggregating thousands of tiny fills in a long-running live session where the running total grows beyond Decimal bounds.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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