nautechsystems/nautilus_trader · error

Actor {actor_id} state callback not found

Error message

Actor {actor_id} state callback not found

What it means

Raised in `Trader::actor_state_callbacks` when building the set of state-save/load callbacks for state recovery: an actor ID was listed for recovery but no callbacks are registered for it in the trader's `actor_state_callbacks` map. This indicates an internal inconsistency — an actor is tracked for persistence without its callback pair.

Source

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

            }
        }

        if errors.is_empty() {
            Ok(())
        } else {
            anyhow::bail!("Failed to save component state: {}", errors.join("; "))
        }
    }

    fn actor_state_callbacks(&self) -> anyhow::Result<Vec<(ActorId, ComponentStateCallbacks)>> {
        self.actor_ids
            .iter()
            .map(|actor_id| {
                self.actor_state_callbacks
                    .get(actor_id)
                    .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")
                    })
            })

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Register the actor's save/load state callbacks when adding it (or use the standard Actor registration path) so the map entry exists
  2. Check whether the actor was added after `load_state` collected its ID and re-order initialization
  3. If using custom trader plumbing, keep `actor_state_callbacks` in sync with registered actors
  4. Report/inspect the specific `actor_id`; rebuild the trader config so only actors with state callbacks are included in recovery
Defensive patterns

Strategy: validation

Validate before calling

// ensure every actor listed for recovery has state callbacks registered
for id in recovery_actor_ids {
    assert!(trader.has_actor_state_callbacks(&id), "missing callbacks for {id}");
}

Type guard

fn has_state_callbacks(trader: &Trader, actor_id: &ActorId) -> bool {
    trader.actor_state_callbacks().contains_key(actor_id)
}

Prevention

When it happens

Trigger: Calling trader start/state save when an actor_id present in the component registry (or persistence list) has no entry in `self.actor_state_callbacks` — e.g. the actor was added without state callbacks, or was removed while still referenced by the recovery list.

Common situations: Custom actor registration paths that skip `save()`/`load()` callback registration; modifying trader internals; a version mismatch where recovery metadata references actors registered differently in the current version.

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