nautechsystems/nautilus_trader · error

Cannot add strategy while node is running, add strategies…

Error message

Cannot add strategy while node is running, add strategies before running the node

What it means

add_strategy registers a trading strategy with the node and, like actor registration, is only permitted while the node is Idle. Calling it on a running node bails with this error to protect execution-engine invariants.

Solutions

  1. Add all strategies before starting the node
  2. Check node.state() == NodeState::Idle before calling in dynamic flows
  3. For runtime strategy changes, use the execution engine's supported dynamic APIs rather than the node-level registration method

Example fix

// before
node.run().await?;
node.add_strategy(my_strategy)?;
// after
node.add_strategy(my_strategy)?;
node.run().await?;
Defensive patterns

Strategy: validation

Validate before calling

if node.state() == NodeState::Idle {
    node.add_strategy(strategy)?;
}

Prevention

When it happens

Trigger: Calling node.add_strategy(strategy) when node.state() != NodeState::Idle — after run/start has been called or while the node is starting/running.

Common situations: Strategies added in reaction to market data or user commands at runtime; setup code ordered after node.run(); configuration loading that completes asynchronously after start.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at crates/live/src/node/mod.rs:2699

    /// Strategies are registered in both the component registry (for lifecycle management)
    /// and the actor registry (for data callbacks via msgbus).
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - The node is currently running.
    /// - A strategy with the same ID is already registered.
    /// - The configured external order instrument IDs repeat an instrument or the cache already
    ///   contains a requested claim.
    /// - The strategy configures one or more external order instrument IDs and the cache is already
    ///   borrowed.
    /// - The strategy configures an OMS type override and the execution engine is already borrowed.
    pub fn add_strategy<T>(&mut self, mut strategy: T) -> anyhow::Result<()>
    where
        T: Strategy + StrategyNative + DataActorNative + Component + Debug + 'static,
    {
        if self.state() != NodeState::Idle {
            anyhow::bail!(
                "Cannot add strategy while node is running, add strategies before running the node"
            );
        }

        // Capture strategy-owned values before adding the strategy, which moves it
        let strategy_id = self
            .kernel
            .trader
            .borrow()
            .prepare_strategy_for_registration(&mut strategy)?;
        let oms_type = StrategyNative::strategy_core(&strategy).config.oms_type;
        let instrument_ids = strategy.external_order_instrument_ids().unwrap_or_default();

        if !instrument_ids.is_empty() {
            self.register_external_order_claims(strategy_id, &instrument_ids)?;
        }

        let mut exec_engine = match oms_type

View on GitHub (pinned to 18893faf8b)