nautechsystems/nautilus_trader · error

Order invariant violated: first event must be OrderInitializ

Error message

Order invariant violated: first event must be OrderInitialized

What it means

`OrderAny::init_event` retrieves the first event of the order and asserts it is an `OrderEventAny::Initialized`. A panic here means the internal order invariant — every order's event log starts with `OrderInitialized` — was violated: either the order was constructed without an init event or events were reordered/removed. This is a protected internal invariant, not a user-recoverable error.

Source

Thrown at crates/model/src/orders/any.rs:116

        Ok(order)
    }

    /// Returns a reference to the [`crate::events::OrderInitialized`] event.
    ///
    /// This is always the first event in the order's event list (invariant).
    ///
    /// # Panics
    ///
    /// Panics if the first event is not `OrderInitialized` (violates invariant).
    #[must_use]
    pub fn init_event(&self) -> &crate::events::OrderInitialized {
        match self
            .events()
            .first()
            .expect("Order invariant violated: no events")
        {
            OrderEventAny::Initialized(init) => init,
            _ => panic!("Order invariant violated: first event must be OrderInitialized"),
        }
    }

    /// Assigns the order to the list identified by `id`.
    ///
    /// # Panics
    ///
    /// Panics if the order has no events or its first event is not `OrderInitialized`.
    pub fn set_order_list_id(&mut self, id: OrderListId) {
        let order: &mut OrderCore = match self {
            Self::Limit(order) => order,
            Self::LimitIfTouched(order) => order,
            Self::Market(order) => order,
            Self::MarketIfTouched(order) => order,
            Self::MarketToLimit(order) => order,
            Self::StopLimit(order) => order,
            Self::StopMarket(order) => order,
            Self::TrailingStopLimit(order) => order,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure every OrderAny is created via its constructor (`OrderAny::new`/initialized from an OrderInitialized event) before any other events are pushed.
  2. When rebuilding event logs, always insert/replay the OrderInitialized event first.
  3. Check serialization/deserialization code so event order is preserved.
  4. Use the `set_order_list_id`-style public mutators instead of mutating `events` directly.

Example fix

// before
let mut order = OrderAny::test_default();
order.events.clear();
let init = order.init_event(); // panics
// after
let order = OrderAny::new(init_event, trader_id, strategy_id, account_id); // init first
let init = order.init_event();
Defensive patterns

Strategy: type-guard

Validate before calling

fn has_valid_init_event(order: &OrderAny) -> bool {
    matches!(order.events().first(), Some(OrderEventAny::Initialized(_)))
}

Type guard

fn first_event_is_initialized(order: &OrderAny) -> Option<&OrderInitialized> {
    match order.events().first() {
        Some(OrderEventAny::Initialized(init)) => Some(init),
        _ => None,
    }
}

Prevention

When it happens

Trigger: Calling `order.init_event()` on an `OrderAny` whose `events` list is non-empty but does not start with `Initialized` (e.g. manually pushed a Submitted/Filled event first, or deserialized a corrupted event log).

Common situations: Custom event-log reconstruction or replay code appending events out of order; test helpers building orders by pushing events manually; serde deserialization of truncated event histories.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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