QuantConnect/Lean · error · AssertionError
Expected order ticket in order event to not be null
Error message
Expected order ticket in order event to not be null
What it means
OrderTicketAssignmentDemoAlgorithm places asynchronous market orders and demonstrates that you cannot rely on the return value being assigned to self.ticket before order events fire. In on_order_event it reads order_event.ticket (the ticket the engine attaches to the event) and asserts it is not None. A None ticket means the engine failed to associate the OrderTicket with the event for that order — a regression in Lean's order-event/ticket wiring.
Source
Thrown at Algorithm.Python/OrderTicketAssignmentDemoAlgorithm.py:44
self._symbol = self.add_equity("SPY").symbol
self.trade_count = 0
self.consolidate(self._symbol, timedelta(hours=1), self.hour_consolidator)
def hour_consolidator(self, bar: TradeBar):
# Reset self.ticket to None on each new bar
self.ticket = None
self.ticket = self.market_order(self._symbol, 1, asynchronous=True)
self.debug(f"{self.time}: Buy: Price {bar.price}, order_id: {self.ticket.order_id}")
self.trade_count += 1
def on_order_event(self, order_event: OrderEvent):
# We cannot access self.ticket directly because it is assigned asynchronously:
# this order event could be triggered before self.ticket is assigned.
ticket = order_event.ticket
if ticket is None:
raise AssertionError("Expected order ticket in order event to not be null")
if order_event.status == OrderStatus.SUBMITTED and self.ticket is not None:
raise AssertionError("Field self.ticket not expected no be assigned on the first order event")
self.debug(ticket.to_string())
def on_end_of_algorithm(self):
# Just checking that orders were placed
if not self.portfolio.invested or self.trade_count != self.transactions.orders_count:
raise AssertionError(f"Expected the portfolio to have holdings and to have {self.trade_count} trades, but had {self.transactions.orders_count}")
View on GitHub (pinned to d2c3659f87)
Solutions
- Confirm the order was user-submitted (via market_order/asynchronous=True); for internal orders, guard with `if order_event.ticket is None: return`.
- If you modified Lean, ensure OrderEvent.Ticket is populated for every user order event path.
- Use order_event.order_id to look up the ticket via self.transactions.get_order_by_id(...) as a fallback.
- Filter out non-user order events (e.g. check order_event.ticket is not None only for OrderStatus you expect).
Example fix
# before
ticket = order_event.ticket
if ticket is None:
raise AssertionError('Expected order ticket in order event to not be null')
# after: tolerate internal orders, look up by id
ticket = order_event.ticket or self.transactions.get_order_ticket(order_event.order_id)
if ticket is None:
return # internal/automatic order without a user ticket Defensive patterns
Strategy: type-guard
Validate before calling
# Prefer the event's ticket; fall back to lookup by order id
ticket = order_event.ticket or self.transactions.get_order_ticket(order_event.order_id)
if ticket is None:
return # internal/automatic order without a user ticket Type guard
def has_ticket(order_event) -> bool:
return order_event.ticket is not None Prevention
- Rely on order_event.ticket (or lookup by order_id) instead of a shared self.ticket variable.
- Guard for internal orders (margin calls, assignments) that may lack a user ticket.
- After Lean changes, verify OrderEvent.Ticket is populated for user orders.
- Tolerate None for non-user event types.
When it happens
Trigger: An OrderEvent arrives in on_order_event whose .ticket property is None. This happens if the engine does not set the ticket reference on the event, if the order was generated internally (e.g. margin call) without a ticket, or after a refactor of OrderEvent.Ticket population.
Common situations: A Lean change decoupling OrderEvent from its OrderTicket; internal/automatic orders (liquidations, margin calls, option assignment/exercise) that legitimately lack a user ticket; a brokerage event path that bypasses ticket assignment.
Related errors
- Field self.ticket not expected no be assigned on the first o
- Expected the portfolio to have holdings and to have {self.tr
- OrderEvent quantity is Not expected to be 0, it should hold
- OrderEvent quantity should hold the current order Quantity
- OrderEvent Ticket was not set
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/1fde803652b65c0c.
Report an issue: GitHub.