nautechsystems/nautilus_trader · critical
Failed to start actor {actor_id}: {start_err}; rollback fail
Error message
Failed to start actor {actor_id}: {start_err}; rollback failed: {rollback_err} What it means
When an actor fails to start, the TradingSystemController attempts to roll back by removing the half-started actor via remove_actor. If the rollback itself also fails, the original start error would be lost, so both errors are combined into this single aggregated error naming the actor, the original start failure, and the rollback failure.
Source
Thrown at crates/system/src/controller.rs:343
if !start {
return Ok(());
}
if let Err(start_err) = self.start_strategy(&strategy_id) {
return Err(self.rollback_strategy_start_failure(strategy_id, start_err));
}
Ok(())
}
fn rollback_actor_start_failure(
&self,
actor_id: ActorId,
start_err: anyhow::Error,
) -> anyhow::Error {
match self.remove_actor(&actor_id) {
Ok(()) => start_err,
Err(rollback_err) => anyhow::anyhow!(
"Failed to start actor {actor_id}: {start_err}; rollback failed: {rollback_err}"
),
}
}
fn rollback_strategy_start_failure(
&self,
strategy_id: StrategyId,
start_err: anyhow::Error,
) -> anyhow::Error {
match self.remove_strategy(&strategy_id) {
Ok(()) => start_err,
Err(rollback_err) => anyhow::anyhow!(
"Failed to start strategy {strategy_id}: {start_err}; rollback failed: {rollback_err}"
),
}
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Fix the root start error ({start_err} in the message) first — the rollback failure is secondary
- Investigate why remove_actor failed: check whether the actor was already removed or the registry is locked/inconsistent
- Add guards so actors are not started twice concurrently for the same ActorId
- Reproduce with logging enabled at DEBUG for the controller to see both failure points in order
Defensive patterns
Strategy: try-catch
Validate before calling
// before start_created_actor
assert!(!controller.has_actor(&actor_id), "actor {actor_id} already registered — would make rollback ambiguous"); Try / catch
match system.start() {
Err(e) if e.to_string().contains("rollback failed") => {
log::error!("actor start AND rollback failed — system state inconsistent, restart required: {e:#}");
// treat the system as unrecoverable; rebuild controller state
}
other => other?,
} Prevention
- Prevent duplicate actor IDs via config validation before system start
- Make remove_actor idempotent/tolerant of already-removed actors to keep rollback reliable
- Log start failures at the source so the combined error can be triaged quickly
When it happens
Trigger: start_created_actor fails to start an actor (start_err), and the subsequent remove_actor cleanup also errors (rollback_err) — e.g. the actor is in a state where it cannot be removed, or the component registry is inconsistent.
Common situations: Actor start failure due to bad configuration compounded by a panicked or dead actor that cannot be removed; double-start races where the actor was already removed by another path; kernel/component state corruption after an earlier failure.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Failed to start strategy {strategy_id}: {start_err}; rollbac
- DataActor {} must be registered before calling `clock_mut()`
- DataActor {} must be registered before calling `clock()` - t
- DataActor {} must be registered before calling `clock_ref()`
- DataActor {} must be registered before calling `cache()` - t
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/92a0e9ccfd97b058.
Report an issue: GitHub.