nautechsystems/nautilus_trader · critical

Failed to start strategy {strategy_id}: {start_err}; rollbac

Error message

Failed to start strategy {strategy_id}: {start_err}; rollback failed: {rollback_err}

What it means

Analogous to the actor variant: when a strategy fails to start, the controller rolls back by removing the strategy via remove_strategy. If that rollback also fails, both the original start error and the rollback error are combined into this message naming the StrategyId.

Source

Thrown at crates/system/src/controller.rs:356

        actor_id: ActorId,
        start_err: anyhow::Error,
    ) -> anyhow::Error {
        match self.remove_actor(&actor_id) {
            Ok(()) => start_err,
            Err(rollback_err) => anyhow::anyhow!(
                "Failed to start actor {actor_id}: {start_err}; rollback failed: {rollback_err}"
            ),
        }
    }

    fn rollback_strategy_start_failure(
        &self,
        strategy_id: StrategyId,
        start_err: anyhow::Error,
    ) -> anyhow::Error {
        match self.remove_strategy(&strategy_id) {
            Ok(()) => start_err,
            Err(rollback_err) => anyhow::anyhow!(
                "Failed to start strategy {strategy_id}: {start_err}; rollback failed: {rollback_err}"
            ),
        }
    }

    fn register_execute_endpoint(&self) {
        let controller_id = self.core.actor_id().inner();
        let handler = TypedHandler::from(move |command: &ControllerCommand| {
            if let Some(mut controller) = try_get_actor_unchecked::<Self>(&controller_id) {
                if let Err(e) = controller.execute(command.clone()) {
                    log::error!("Controller command failed for {controller_id}: {e}");
                }
            } else {
                log::error!("Controller {controller_id} not found for command handling");
            }
        });

        get_message_bus()

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Address the original start error ({start_err} in the message) — it is the primary cause
  2. Check why remove_strategy failed: duplicate registration, already-removed strategy, or a locked registry
  3. Ensure strategy IDs are unique across the trading system config
  4. Run the strategy in isolation with debug logging to isolate the start failure from the rollback failure
Defensive patterns

Strategy: try-catch

Validate before calling

// before start_created_strategy
assert!(!controller.has_strategy(&strategy_id), "strategy {strategy_id} already registered");

Try / catch

match system.start() {
    Err(e) if e.to_string().contains("rollback failed") => {
        log::error!("strategy start AND rollback failed — rebuild controller state: {e:#}");
    }
    other => other?,
}

Prevention

When it happens

Trigger: start_created_strategy fails during strategy start (bad config, failed on_start handler), and remove_strategy then also errors because the strategy cannot be cleanly removed from the controller's registry.

Common situations: Strategy on_start panics or errors due to missing instruments/accounts, compounded by registry inconsistency; duplicate strategy IDs causing removal to fail; strategy stuck in a starting state that blocks removal.

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/7ba266127fb94949. Report an issue: GitHub.