QuantConnect/Lean · error · AssertionError
OrderEvent Ticket was not set
Error message
OrderEvent Ticket was not set
What it means
Self-test assertion confirming that every OrderEvent delivered to the algorithm carries a back-reference to its OrderTicket. OrderEvent.Ticket is a JsonIgnore, runtime-only property (not serialized) that the transaction processor attaches when the event is dispatched to OnOrderEvent. The assertion fires when that Ticket reference is None/null on arrival.
Source
Thrown at Algorithm.Python/OrderTicketDemoAlgorithm.py:406
order = self.transactions.get_order_by_id(order_event.order_id)
self.log("{0}: {1}: {2}".format(self.time, order.type, order_event))
if order_event.quantity == 0:
raise AssertionError("OrderEvent quantity is Not expected to be 0, it should hold the current order Quantity")
if order_event.quantity != order.quantity:
raise AssertionError("OrderEvent quantity should hold the current order Quantity")
if (type(order) is LimitOrder and order_event.limit_price == 0 or
type(order) is StopLimitOrder and order_event.limit_price == 0):
raise AssertionError("OrderEvent LimitPrice is Not expected to be 0 for LimitOrder and StopLimitOrder")
if type(order) is StopMarketOrder and order_event.stop_price == 0:
raise AssertionError("OrderEvent StopPrice is Not expected to be 0 for StopMarketOrder")
# We can access the order ticket from the order event
if order_event.ticket is None:
raise AssertionError("OrderEvent Ticket was not set")
if order_event.order_id != order_event.ticket.order_id:
raise AssertionError("OrderEvent.ORDER_ID and order_event.ticket.order_id do not match")
def check_pair_orders_for_fills(self, long_order, short_order):
if long_order.status == OrderStatus.FILLED:
self.log("{0}: Cancelling short order, long order is filled.".format(short_order.order_type))
short_order.cancel("Long filled.")
return True
if short_order.status == OrderStatus.FILLED:
self.log("{0}: Cancelling long order, short order is filled.".format(long_order.order_type))
long_order.cancel("Short filled")
return True
return False
def time_is(self, day, hour, minute):View on GitHub (pinned to d2c3659f87)
Solutions
- As an engine regression: ensure the transaction manager sets OrderEvent.Ticket from the OrderTicket before invoking OnOrderEvent.
- If you replay/deserialize events: re-attach the ticket via self.transactions.get_order_ticket(order_event.order_id) (or the equivalent order-ticket lookup) before processing.
- In your own handler: guard against None and resolve the ticket by order id rather than asserting.
- Avoid constructing OrderEvent instances by hand for dispatch; route through the transaction processor so the ticket is attached.
Example fix
# before
if order_event.ticket is None:
raise AssertionError("OrderEvent Ticket was not set")
# after (resolve the ticket when the runtime reference is missing, e.g. on replay)
ticket = order_event.ticket or self.transactions.get_order_ticket(order_event.order_id)
if ticket is None:
raise AssertionError(f"No OrderTicket found for order id {order_event.order_id}") Defensive patterns
Strategy: validation
Validate before calling
# Resolve the ticket defensively; Ticket is runtime-only and missing on replay/deserialized events
ticket = order_event.ticket
if ticket is None:
ticket = self.transactions.get_order_ticket(order_event.order_id)
if ticket is None:
self.debug(f"No ticket for order {order_event.order_id}; cannot process event")
return Type guard
def get_event_ticket(algorithm, order_event):
"""Return the OrderTicket for an event, resolving it when the runtime ref is missing."""
return order_event.ticket or algorithm.transactions.get_order_ticket(order_event.order_id) Prevention
- Never assume order_event.ticket is populated; it is JsonIgnore and absent on deserialized events.
- When replaying stored events, re-attach tickets via the transaction manager before dispatch.
- Route order creation through the transaction processor so the ticket is attached automatically.
When it happens
Trigger: An OrderEvent reaches on_order_event with order_event.ticket is None. This happens when the event was constructed or deserialized on a path that bypasses the transaction handler's ticket-attachment step (e.g. a manually built event, a replay/deserialized packet, or an engine change that stopped setting Ticket before delivery). Because Ticket is [JsonIgnore], events restored from JSON will never carry it unless re-attached.
Common situations: Lean contributors hit this after refactoring the order-event dispatch in the algorithm transaction manager. Users hit it when they synthesize or replay OrderEvent objects (e.g. from a stored result packet) and pass them straight to a handler. It also appears after version upgrades if the dispatch contract for attaching the ticket changed.
Related errors
- OrderEvent.ORDER_ID and order_event.ticket.order_id do not m
- OrderEvent LimitPrice is Not expected to be 0 for LimitOrder
- OrderEvent StopPrice is Not expected to be 0 for StopMarketO
- Order was not canceled
- There should be no open orders
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/b1feec0ebbf46ce0.
Report an issue: GitHub.