nautechsystems/nautilus_trader · critical

Failed to load actor and strategy state: {e:#}

Error message

Failed to load actor and strategy state: {e:#}

What it means

During `Kernel::start_trader`, if `load_state` is enabled the trader calls `Trader::load_state` to restore actor/strategy persisted state from the cache database. Any failure (deserialization, missing/corrupt snapshot, DB error) is wrapped into this anyhow error and aborts startup.

Source

Thrown at crates/system/src/kernel.rs:796

    /// # Errors
    ///
    /// Returns an error if the trader or a registered component fails to start. A failed partial
    /// start is stopped immediately before the error is returned.
    pub fn start_trader(&mut self) -> anyhow::Result<()> {
        log::info!("Starting trader...");

        let load_state = self.config.load_state();
        let save_state = self.config.save_state();

        if (load_state || save_state) && !self.cache.borrow().has_backing() {
            log::warn!(
                "Cache has no database backing, load_state={load_state} and save_state={save_state} will have no effect"
            );
        }

        if load_state {
            Trader::load_state(&self.trader)
                .map_err(|e| anyhow::anyhow!("Failed to load actor and strategy state: {e:#}"))?;
        }

        self.state_save_armed = save_state;
        self.order_emulator.start();

        if let Err(start_err) = Trader::start_with_component_callbacks(&self.trader) {
            let stop_result = self.stop_trader_after_start_failure();
            self.order_emulator.stop();
            let save_result = self.save_trader_state();

            let mut errors = vec![format!("Failed to start trader: {start_err}")];
            if let Err(e) = stop_result {
                errors.push(format!("failed to stop partial trader start: {e}"));
            }

            if let Err(e) = save_result {
                errors.push(format!("failed to save partial trader state: {e}"));
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the inner `{e:#}` chain to identify the root cause (which actor/strategy or key failed).
  2. Verify the cache database config (path/connection) and that the DB is reachable and readable.
  3. Re-export or regenerate state with the current nautilus_trader version, or start with `load_state=false` if a clean start is acceptable.
  4. Restore from a known-good backup of the streaming/state store.

Example fix

// before
config = TradingNodeConfig(cache=CacheConfig(database=DatabaseConfig(type="redis")), load_state=True)

// after
# first verify/repair state, or start clean:
config = TradingNodeConfig(cache=CacheConfig(database=DatabaseConfig(type="redis")), load_state=False)
Defensive patterns

Strategy: try-catch

Validate before calling

# before starting with load_state=True, confirm the backing store is reachable
import redis
r = redis.Redis(host="localhost", port=6379)
r.ping()

Try / catch

try:
    node = TradingNode(config=config)  # load_state=True
    node.start()
except Exception as e:
    logging.error("State load failed: %s", e)
    config.load_state = False  # fall back to a clean start
    node = TradingNode(config=config)
    node.start()

Prevention

When it happens

Trigger: Configuring a kernel/node with `load_state=true` while the backing cache database is missing, corrupt, or holds state written by an incompatible schema/serializer version.

Common situations: Restoring a trader against a Redis/Postgres/backed cache after a nautilus_trader version upgrade changed the state schema; pointing at a database directory that was deleted; corrupted snapshot files.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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