nautechsystems/nautilus_trader · error · anyhow::Error

fill notional overflow while aggregating fill group

Error message

fill notional overflow while aggregating fill group

What it means

This error is thrown when computing a single fill's notional value during fill-group aggregation: `fill.last_qty.as_decimal().checked_mul(fill.last_px.as_decimal())` overflowed. The library uses checked Decimal arithmetic for money values and aborts rather than produce a wrapped (wrong) notional. It means a fill's quantity times price exceeds Decimal capacity or one of the values is corrupt.

Source

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

        }

        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,
            "fill group quantity is not positive"
        );

        let order_qty = Quantity::from_decimal_dp(quantity, instrument.size_precision())?;
        let avg_px = notional
            .checked_div(quantity)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log and inspect the offending fill's `last_qty` and `last_px` to identify which value is abnormally large
  2. Verify the adapter converts venue price/quantity into the instrument's defined precision correctly (not raw ticks or raw size)
  3. Check the instrument definition's price_precision/size_precision matches the venue
  4. If data is genuinely huge, split the aggregation or report upstream — Decimal bounds should not be hit by realistic fills

Example fix

// before: price from raw ticks, unscaled
let px = Price::from_raw(raw_tick, 0);
// after: apply instrument price precision
let px = Price::from_raw(raw_tick, instrument.price_precision());
Defensive patterns

Strategy: validation

Validate before calling

fn fill_notional_representable(fill: &Fill) -> bool {
    fill.last_qty
        .as_decimal()
        .checked_mul(fill.last_px.as_decimal())
        .map(|n| n < Decimal::from(10u64.pow(30)))
        .unwrap_or(false)
}

Type guard

fn has_plausible_fill(f: &Fill, max_notional: Decimal) -> bool {
    f.last_qty.as_decimal() > Decimal::ZERO
        && f.last_px.as_decimal() > Decimal::ZERO
        && f.last_qty.as_decimal().checked_mul(f.last_px.as_decimal())
            .map(|n| n <= max_notional)
            .unwrap_or(false)
}

Try / catch

match manager.aggregate_fill_group(&fills) {
    Ok(r) => handle(r),
    Err(e) if e.to_string().contains("fill notional overflow") => {
        log::error!("fill notional overflow: {e}");
        quarantine_fills(&fills);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Processing a fill whose `last_qty * last_px` product exceeds the internal Decimal maximum — e.g. a huge quantity combined with a high price, a fill with a corrupted/malformed `last_px` or `last_qty` from the venue adapter, or wrongly scaled values (price in raw ticks, quantity unscaled).

Common situations: Exchange adapter reporting price or quantity in raw integer representation without applying precision scaling; instrument definition with wrong price precision causing absurd decimal magnitudes; corrupted historical fill data replayed during live reconciliation; extremely high-priced instruments with large fill sizes near arithmetic 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/a00b13ff6754ca15. Report an issue: GitHub.