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
- Ensure strategies are added through the standard path so their state callbacks are registered
- Avoid removing/retiring a strategy while state save/load is in progress; serialize lifecycle operations
- Keep recovery metadata in sync with `strategy_state_callbacks` after `remove_strategy`/`retire_strategy`
- 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
- Add strategies via the standard registration path so callbacks exist
- Serialize strategy retirement with state save/load passes
- Update recovery metadata immediately after `remove_strategy`/`retire_strategy`
- Audit for strategies configured for recovery but registered without callbacks
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
- Actor {actor_id} state callback not found
- Cannot add strategy while node is running, add strategies be
- Failed to load strategy {strategy_id} state: {e:#}
- Failed to restore strategy {strategy_id} state: {e:#}
- Python on_degrade failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/a8732939a2b90c09.
Report an issue: GitHub.