nautechsystems/nautilus_trader · error
Failed to restore strategy {strategy_id} state: {e:#}
Error message
Failed to restore strategy {strategy_id} state: {e:#} What it means
Raised in `Trader::load_state` when a strategy's registered `on_load` state-restoration callback returns an error. The persisted state was read from the cache successfully, but the strategy could not restore it, so recovery aborts with this message.
Source
Thrown at crates/system/src/trader.rs:1606
};
(callbacks.load)(actor_id.inner(), state)
.map_err(|e| anyhow::anyhow!("Failed to restore actor {actor_id} state: {e:#}"))?;
}
for (strategy_id, callbacks) in strategy_callbacks {
let state = cache
.borrow()
.load_strategy_state(&strategy_id)
.map_err(|e| {
anyhow::anyhow!("Failed to load strategy {strategy_id} state: {e:#}")
})?;
let Some(state) = state.filter(|state| !state.is_empty()) else {
continue;
};
(callbacks.load)(strategy_id.inner(), state).map_err(|e| {
anyhow::anyhow!("Failed to restore strategy {strategy_id} state: {e:#}")
})?;
}
Ok(())
}
/// Saves actor and strategy state in registration order.
///
/// Empty state is persisted, while a cache without database backing does not invoke
/// component callbacks. All callbacks and updates receive an attempt before errors return.
///
/// # Errors
///
/// Returns an error containing every component callback or persistence failure.
pub(crate) fn save_state(trader: &Rc<RefCell<Self>>) -> anyhow::Result<()> {
let (cache, actor_callbacks, strategy_callbacks) = {
let trader = trader.borrow();
let actor_callbacks = trader.actor_state_callbacks()?;View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the wrapped `{e:#}` for the exact restore failure and align the load callback with the persisted schema
- Ensure the strategy implementation/version that saved the state matches the one restoring it; add migration logic to the load callback if needed
- Delete the strategy's stale persisted key so it starts with empty state, then let it re-save
- Keep library versions consistent between state-saving and state-restoring runs
Defensive patterns
Strategy: try-catch
Validate before calling
// round-trip check the strategy state before relying on recovery let state = cache.load_strategy_state(&strategy_id)?; strategy.test_restore(state.clone())?;
Try / catch
do {
system.start_with_recovery()
} catch e if e.contains("Failed to restore strategy") => {
// migrate the schema or delete the stale key, then restart
} Prevention
- Version and migration-test strategy state schemas across releases
- Save/restore with the identical strategy type and library version
- Round-trip test save/load in CI for every strategy
- Delete stale keys intentionally when a strategy's state layout changes
When it happens
Trigger: Trader start with state recovery enabled; the cache returns non-empty state for the strategy and the strategy's `load` callback errors — typically because the saved payload does not match the strategy's current state schema (version upgrade, changed fields, wrong strategy type).
Common situations: Restarting after a nautilus upgrade with state saved by the older version; refactoring a strategy's saved-state struct without a migration; a cache shared between configurations containing state for a different strategy instance.
Related errors
- Failed to restore actor {actor_id} state: {e:#}
- Failed to load strategy {strategy_id} state: {e:#}
- Cannot add strategy while node is running, add strategies be
- Failed to load actor {actor_id} state: {e:#}
- Strategy {strategy_id} state callback not found
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c516580c885a469a.
Report an issue: GitHub.