nautechsystems/nautilus_trader · error

Strategy {strategy_id} state callback not found

Error message

Strategy {strategy_id} state callback not found

What it means

Raised in `Trader::strategy_state_callbacks` when a strategy ID listed for state recovery has no registered save/load callbacks in the trader's `strategy_state_callbacks` map. The trader cannot persist or restore that strategy's state, so it errors rather than silently skipping it.

Source

Thrown at crates/system/src/trader.rs:1689

                    .copied()
                    .map(|callbacks| (*actor_id, callbacks))
                    .ok_or_else(|| anyhow::anyhow!("Actor {actor_id} state callback not found"))
            })
            .collect()
    }

    fn strategy_state_callbacks(
        &self,
    ) -> anyhow::Result<Vec<(StrategyId, ComponentStateCallbacks)>> {
        self.strategy_ids
            .iter()
            .map(|strategy_id| {
                self.strategy_state_callbacks
                    .get(strategy_id)
                    .copied()
                    .map(|callbacks| (*strategy_id, callbacks))
                    .ok_or_else(|| {
                        anyhow::anyhow!("Strategy {strategy_id} state callback not found")
                    })
            })
            .collect()
    }

    fn load_component_state<T>(
        component_id: Ustr,
        state: PersistedComponentState,
    ) -> anyhow::Result<()>
    where
        T: DataActor + DataActorNative + Debug + 'static,
    {
        let mut component = try_get_actor_unchecked::<T>(&component_id).ok_or_else(|| {
            anyhow::anyhow!("Component {component_id} not found in actor registry")
        })?;
        component.on_load(state)
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure strategies are added through the standard path so their state callbacks are registered
  2. Avoid removing/retiring a strategy while state save/load is in progress; serialize lifecycle operations
  3. Keep recovery metadata in sync with `strategy_state_callbacks` after `remove_strategy`/`retire_strategy`
  4. Check the reported `strategy_id` against your configured strategies and drop it from recovery if intentionally removed
Defensive patterns

Strategy: validation

Validate before calling

// before state save/load, confirm each strategy has callbacks
for id in recovery_strategy_ids {
    assert!(trader.has_strategy_state_callbacks(&id), "missing callbacks for {id}");
}

Type guard

fn has_strategy_callbacks(trader: &Trader, strategy_id: &StrategyId) -> bool {
    trader.strategy_state_callbacks().contains_key(strategy_id)
}

Prevention

When it happens

Trigger: Calling trader start/state save while a strategy_id referenced by recovery has no callback entry — typically the strategy was registered without state callbacks, or was removed (e.g. via `retire_strategy`, which clears `strategy_state_callbacks`) while still referenced by the recovery path.

Common situations: Removing a strategy concurrently with a state-save pass; custom strategy registration bypassing the standard callback registration; stale recovery metadata referencing a retired strategy.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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