nautechsystems/nautilus_trader · error · anyhow::Error

Failed to send account state: {e}

Error message

Failed to send account state: {e}

What it means

generate_account_state builds an AccountState event and sends it through the shared execution event sender channel; if the channel send fails (receiver dropped or closed), the error is wrapped with anyhow::anyhow! into 'Failed to send account state: {e}'. This means the execution engine can no longer receive account updates, usually because the live execution engine has shut down or the channel was disconnected.

Source

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

        info: Option<Params>,
    ) -> anyhow::Result<()> {
        let factory = OrderEventFactory::new(
            self.core.trader_id,
            self.core.account_id,
            self.core.account_type,
            self.core.base_currency,
        );
        let state = factory.generate_account_state(
            balances,
            margins,
            reported,
            ts_event,
            get_atomic_clock_realtime().get_time_ns(),
            info,
        );
        get_exec_event_sender()
            .send(ExecutionEvent::Account(state))
            .map_err(|e| anyhow::anyhow!("Failed to send account state: {e}"))
    }

    fn start(&mut self) -> anyhow::Result<()> {
        // Start is handled by connect() for live clients
        Ok(())
    }

    fn stop(&mut self) -> anyhow::Result<()> {
        self.begin_task_shutdown();
        Ok(())
    }

    fn submit_order(&self, cmd: SubmitOrder) -> anyhow::Result<()> {
        let order = self.core.get_order(&cmd.client_order_id)?;
        if let Err(reason) = validate_order(&order) {
            let reason = reason.to_string();
            Self::send_order_denied(
                cmd.order_init.trader_id,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the execution engine outlives the IB client or stop account subscriptions before tearing down the engine.
  2. Check shutdown ordering in the trading node: unsubscribe/stop the data and execution clients before dropping the engine and its event channel.
  3. Inspect logs preceding this error for engine panics or disconnects that closed the event channel unexpectedly.

Example fix

// before
get_exec_event_sender()
    .send(ExecutionEvent::Account(state))
    .map_err(|e| anyhow::anyhow!("Failed to send account state: {e}"))
// after
match get_exec_event_sender().send(ExecutionEvent::Account(state)) {
    Ok(()) => Ok(()),
    Err(e) if e.is_disconnected() => {
        tracing::debug!("Execution event channel closed; dropping account state update");
        Ok(())
    }
    Err(e) => Err(anyhow::anyhow!("Failed to send account state: {e}")),
}
Defensive patterns

Strategy: try-catch

Validate before calling

fn event_channel_alive(sender: &Sender<ExecutionEvent>) -> bool {
    !sender.is_closed()
}

Try / catch

match get_exec_event_sender().send(ExecutionEvent::Account(state)) {
    Err(e) if e.is_disconnected() => tracing::debug!("Engine channel closed during shutdown"),
    Err(e) => return Err(anyhow::anyhow!("Failed to send account state: {e}")),
    Ok(()) => {}
}

Prevention

When it happens

Trigger: A IB account summary/balance update arrives and generate_account_state tries send() on the ExecutionEvent channel while the receiving ExecutionEngine has been stopped, dropped, or its receiver disconnected.

Common situations: Shutting down a trading node while account subscription updates are still streaming in; an execution engine panic or disconnect closing the channel; race between client teardown and in-flight account events.

Related errors


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