nautechsystems/nautilus_trader · error

Invalid `OrderEventAny` not `OrderFilled`, was {event:?}

Error message

Invalid `OrderEventAny` not `OrderFilled`, was {event:?}

What it means

The From<OrderEventAny> for OrderFilled conversion panics when the event is any variant other than OrderEventAny::Filled. It is an unchecked narrowing conversion intended only for call sites already certain the event is a fill.

Source

Thrown at crates/model/src/events/order/any.rs:326

            Self::CancelRejected(event) => Some(event.reason),
            Self::Updated(_) => None,
            Self::Filled(_) => None,
            Self::FillVoided(event) => event.reason,
        }
    }
}

/// Converts an `OrderEventAny` into an `OrderFilled`.
///
/// # Panics
///
/// Panics if `event` is not a `Filled` variant.
impl From<OrderEventAny> for OrderFilled {
    #[inline]
    fn from(event: OrderEventAny) -> Self {
        match event {
            OrderEventAny::Filled(event) => event,
            _ => panic!("Invalid `OrderEventAny` not `OrderFilled`, was {event:?}"),
        }
    }
}

impl Display for OrderEventAny {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Initialized(e) => write!(f, "{e}"),
            Self::Denied(e) => write!(f, "{e}"),
            Self::Emulated(e) => write!(f, "{e}"),
            Self::Released(e) => write!(f, "{e}"),
            Self::Submitted(e) => write!(f, "{e}"),
            Self::Accepted(e) => write!(f, "{e}"),
            Self::Rejected(e) => write!(f, "{e}"),
            Self::Canceled(e) => write!(f, "{e}"),
            Self::Expired(e) => write!(f, "{e}"),
            Self::Triggered(e) => write!(f, "{e}"),
            Self::PendingUpdate(e) => write!(f, "{e}"),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Match on OrderEventAny::Filled(event) explicitly instead of using From
  2. Filter the event stream to fills before converting
  3. If a general conversion is needed, add a helper returning Option<OrderFilled>

Example fix

// before
let fill = OrderFilled::from(event); // panics for non-fill events
// after
let fill = match event {
    OrderEventAny::Filled(f) => f,
    other => { /* skip or log */ return; }
};
Defensive patterns

Strategy: type-guard

Validate before calling

fn as_order_filled(event: &OrderEventAny) -> Option<&OrderFilled> {
    match event {
        OrderEventAny::Filled(f) => Some(f),
        _ => None,
    }
}

Type guard

fn is_filled(event: &OrderEventAny) -> bool {
    matches!(event, OrderEventAny::Filled(_))
}

Try / catch

let fill = match event {
    OrderEventAny::Filled(f) => f,
    other => { debug!("ignoring non-fill event {other:?}"); return; }
};

Prevention

When it happens

Trigger: Calling OrderFilled::from(event) (or .into()) on an OrderInitialized, OrderSubmitted, OrderCanceled, or any other non-Filled OrderEventAny.

Common situations: Position/report code subscribing to all order events and casting without matching; changes in event flow delivering other event types where only fills were previously expected.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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