nautechsystems/nautilus_trader · error · anyhow::Error

Failed to send order cancel rejected event: {e}

Error message

Failed to send order cancel rejected event: {e}

What it means

`send_order_cancel_rejected` sends an `OrderEventAny::CancelRejected` event on the unbounded mpsc `exec_sender`. A send error means the receiving end has been closed; the anyhow wrapper reports that the cancel-rejected event could not be delivered.

Source

Thrown at crates/adapters/interactive_brokers/src/execution/core.rs:1976

        ts_event: UnixNanos,
        account_id: AccountId,
    ) -> anyhow::Result<()> {
        let event = OrderCancelRejected::new(
            target_order.trader_id(),
            target_order.strategy_id(),
            target_order.instrument_id(),
            target_order.client_order_id(),
            Ustr::from(reason),
            UUID4::new(),
            ts_event,
            ts_event,
            false,
            target_order.venue_order_id(),
            Some(account_id),
        );
        exec_sender
            .send(ExecutionEvent::Order(OrderEventAny::CancelRejected(event)))
            .map_err(|e| anyhow::anyhow!("Failed to send order cancel rejected event: {e}"))
    }
}

#[allow(dead_code)]
impl InteractiveBrokersExecutionClient {
    fn parse_historical_fill_report(
        &self,
        cmd: &GenerateFillReports,
        exec_data: &ExecutionData,
        commission: f64,
        commission_currency: &str,
        ts_init: UnixNanos,
    ) -> Option<FillReport> {
        let instrument_id = match self.resolve_historical_execution_instrument_id(exec_data) {
            Ok(instrument_id) => instrument_id,
            Err(e) => {
                Self::warn_historical_fill_report_parse_error(exec_data, &e);
                return None;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Order shutdown so the IB adapter is disconnected before the execution event loop is dropped.
  2. Check for code issuing cancels after engine teardown and gate commands on node liveness.
  3. If unavoidable at shutdown, handle the send error as a warning rather than a hard failure.

Example fix

// before
exec_sender
    .send(ExecutionEvent::Order(OrderEventAny::CancelRejected(event)))
    .map_err(|e| anyhow::anyhow!("Failed to send order cancel rejected event: {e}"))
// after
exec_sender
    .send(ExecutionEvent::Order(OrderEventAny::CancelRejected(event)))
    .map_err(|e| anyhow::anyhow!("Failed to send order cancel rejected event: {e}"))
    .or_else(|e| { log::warn!("cancel rejected event dropped at shutdown: {e}"); Ok::<(), anyhow::Error>(()) })
Defensive patterns

Strategy: try-catch

Try / catch

// During teardown, downgrade send failures to warnings
if exec_sender.send(ExecutionEvent::Order(OrderEventAny::CancelRejected(event))).is_err() {
    log::warn!("cancel rejected event lost during shutdown");
}

Prevention

When it happens

Trigger: IB rejects a cancel request (e.g. order already filled or unknown to TWS) and, while emitting the CancelRejected event, the channel receiver has been dropped — event loop stopped or node shutdown in progress.

Common situations: Stale cancel for an already-filled order arriving at shutdown; racing teardown where the IB callback fires after the execution engine is dropped; duplicated cancel commands after reconnect.

Related errors


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