nautechsystems/nautilus_trader · error · anyhow::Error
Failed to send order canceled event: {e}
Error message
Failed to send order canceled event: {e} What it means
The adapter received an order-canceled status from IB but could not forward the resulting OrderCanceled event through the exec_sender channel because the receiver was dropped. Like the other send failures in core_updates.rs, it signals that the execution event pipeline is no longer accepting events while IB callbacks continue to arrive.
Source
Thrown at crates/adapters/interactive_brokers/src/execution/core_updates.rs:603
strategy_id_map,
)?;
let event = OrderCanceled::new(
trader_id,
strategy_id,
instrument_id,
client_order_id,
UUID4::new(),
ts_init,
ts_init,
false,
Some(venue_order_id),
Some(account_id),
None,
);
exec_sender
.send(ExecutionEvent::Order(OrderEventAny::Canceled(event)))
.map_err(|e| anyhow::anyhow!("Failed to send order canceled event: {e}"))?;
tracing::debug!("Order {} canceled", client_order_id);
}
Some(IbOrderStatus::PendingCancel) => {
Self::emit_order_pending_cancel(
status.order_id,
client_order_id,
venue_order_id,
instrument_id_map,
trader_id_map,
strategy_id_map,
pending_cancel_orders,
exec_sender,
ts_init,
account_id,
)?;
tracing::debug!("Order {} pending cancel", client_order_id);
}
_ => {View on GitHub (pinned to 18893faf8b)
Solutions
- Keep the ExecutionEngine/event receiver alive until the IB adapter is fully disconnected.
- Disconnect the IB client and stop order-status handling before dropping the receiver during shutdown.
- Treat send failures during intentional shutdown as benign and log them instead of erroring.
Example fix
// before
exec_sender
.send(ExecutionEvent::Order(OrderEventAny::Canceled(event)))
.map_err(|e| anyhow::anyhow!("Failed to send order canceled event: {e}"))?;
// after
if let Err(e) = exec_sender.send(ExecutionEvent::Order(OrderEventAny::Canceled(event))) {
tracing::warn!("Execution channel closed, dropping order canceled event: {e}");
}
tracing::debug!("Order {} canceled", client_order_id); Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: skip event emission if the consumer is gone
if exec_sender.is_closed() {
tracing::warn!("Execution event channel closed; order canceled event dropped");
return Ok(());
} Type guard
fn receiver_alive(sender: &mpsc::Sender<ExecutionEvent>) -> bool {
!sender.is_closed()
} Try / catch
if let Err(e) = exec_sender.send(ExecutionEvent::Order(OrderEventAny::Canceled(event))) {
tracing::warn!("Order canceled event dropped: {e}");
} Prevention
- Keep the ExecutionEngine running until the IB adapter reports disconnected
- Drain in-flight IB order status callbacks before shutdown completes
- Add integration tests that cancel orders during shutdown
When it happens
Trigger: handle_order_status matches IbOrderStatus::Cancelled, builds an OrderCanceled event, and calls exec_sender.send(...); the send fails because the channel receiver was dropped or closed before this callback ran.
Common situations: Node/engine stopped or cancelled while IB Gateway still reports cancellations; race between engine shutdown and in-flight order status messages; consumer task terminated by an earlier error.
Related errors
- Failed to send order updated event: {e}
- Failed to send order rejected event: {e}
- failed to request logging sync: {e}
- failed to receive logging sync acknowledgement: {e}
- Failed to send delete order command: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/dcb144f50b390e0a.
Report an issue: GitHub.