nautechsystems/nautilus_trader · error

fill raw bounds pre-checked

Error message

fill raw bounds pre-checked

What it means

When applying an OrderFilled event, filled() sums the raw quantity values with checked_quantity_quantity_raw_sum and unwraps the result, asserting the raw bounds were validated earlier in the fill path (quantity can't exceed raw u64 bounds at the order's precision). If the check fails here, an upstream pre-check was skipped or the fill is pathological.

Source

Thrown at crates/model/src/orders/mod.rs:1269

        if event.reconciliation && !self.filled_qty.is_zero() && event.quantity == self.filled_qty {
            self.status = OrderStatus::Filled;
            self.ts_closed = Some(event.ts_event);
        }

        if let Some(venue_order_id) = &event.venue_order_id
            && (self.venue_order_id.is_none()
                || venue_order_id != self.venue_order_id.as_ref().unwrap())
        {
            self.venue_order_id = Some(*venue_order_id);
            self.venue_order_ids.push(*venue_order_id);
        }

        self.is_quote_quantity = event.is_quote_quantity;
    }

    fn filled(&mut self, event: &OrderFilled, source_status: OrderStatus) {
        let raw = checked_quantity_raw_sum(self.filled_qty.raw, event.last_qty.raw)
            .expect("fill raw bounds pre-checked");
        let new_filled_qty = Quantity::from_raw(raw, self.filled_qty.precision);

        // Calculate overfill if any
        if new_filled_qty > self.quantity {
            let overfill_raw = new_filled_qty.raw - self.quantity.raw;
            self.overfill_qty = quantity_from_domain_raw(
                self.overfill_qty.raw.saturating_add(overfill_raw),
                self.filled_qty.precision,
            );
        }

        let new_leaves_qty = self.leaves_qty.saturating_sub(event.last_qty);

        if new_filled_qty >= self.quantity {
            self.status = OrderStatus::Filled;
            self.ts_closed = Some(event.ts_event);
        } else if new_leaves_qty.is_zero() && !self.voided_qty.is_zero() {
            self.status = OrderStatus::Voided;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Validate each fill's last_qty against the remaining quantity (leaves_qty) before applying the OrderFilled event
  2. Use try_from / checked arithmetic when constructing events from external venue data
  3. For replay, use the library's replay/adjustment APIs (e.g. apply adjustment paths) rather than direct event application with unvalidated quantities

Example fix

// before
order.apply(event); // OrderFilled with unvalidated qty
// after
if event.last_qty > order.leaves_qty() {
    // clamp, reject, or log the anomalous fill
    return;
}
order.apply(event);
Defensive patterns

Strategy: validation

Validate before calling

// Rust: before applying OrderFilled
assert!(event.last_qty <= order.leaves_qty(), "fill exceeds remaining quantity");
order.apply(event);

Type guard

fn fill_valid(o: &dyn Order, ev: &OrderFilled) -> bool { ev.last_qty <= o.leaves_qty() }

Prevention

When it happens

Trigger: Applying an OrderFilled whose last_qty, added to the running filled_qty, overflows/underflows the raw fixed-precision bounds — i.e. a fill not pre-validated against the order quantity.

Common situations: Feeding synthetic or replayed fill events with quantities beyond the order's size; venue backfill producing fills exceeding total quantity at extreme precision; custom event replay code bypassing the normal fill validation.

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/9466e4ef87255234. Report an issue: GitHub.