nautechsystems/nautilus_trader · error · anyhow::Error
DataActor {actor_id} already registered with trader {existin
Error message
DataActor {actor_id} already registered with trader {existing_trader_id} What it means
`DataActor::register` refuses to run twice. If the actor already holds a `trader_id`, calling registration again would silently re-bind the actor to another trader; the library bails instead, preserving a one-to-one actor/trader relationship for the actor's lifetime.
Source
Thrown at crates/common/src/actor/data_actor.rs:4129
)
});
CacheApi::new(cache.as_ref())
}
/// Register the data actor with a trader.
///
/// # Errors
///
/// Returns an error if the actor has already been registered with a trader
/// or if the provided dependencies are invalid.
pub fn register(
&mut self,
trader_id: TraderId,
clock: Rc<RefCell<dyn Clock>>,
cache: Rc<RefCell<Cache>>,
) -> anyhow::Result<()> {
if let Some(existing_trader_id) = self.trader_id {
anyhow::bail!(
"DataActor {} already registered with trader {existing_trader_id}",
self.actor_id
);
}
// Validate clock by attempting to access it
{
let _timestamp = clock.borrow().timestamp_ns();
}
// Validate cache by attempting to access it
{
let _cache_borrow = cache.borrow();
}
self.trader_id = Some(trader_id);
self.clock = Some(clock);
self.cache = Some(cache);View on GitHub (pinned to 18893faf8b)
Solutions
- Create a new DataActor instance for the new registration
- Ensure each actor is registered exactly once per trader lifecycle
- If re-registering after a partial failure is intended, reset/rebuild the actor instead of reusing it
Example fix
// before actor.register(trader_id_a.clone(), ...); actor.register(trader_id_b.clone(), ...); // bails // after let actor_a = MyActor::new(); let actor_b = MyActor::new(); actor_a.register(trader_id_a, ...); actor_b.register(trader_id_b, ...);
Defensive patterns
Strategy: validation
Validate before calling
if actor_is_registered(&actor) {
return Err(anyhow::anyhow!("actor already registered; create a new instance"));
} Type guard
fn is_unregistered(actor: &DataActor) -> bool {
actor.trader_id().is_none()
} Try / catch
if let Err(e) = actor.register(trader_id, clock.clone(), cache.clone()) {
log::warn!("registration skipped: {e}"); // treat double-registration as idempotent no-op if safe
} Prevention
- Register each actor exactly once per lifecycle
- Never share actor instances between traders
- Rebuild actors on trader restart instead of reusing them
When it happens
Trigger: Calling `register(trader_id, clock, cache)` on a DataActor that was previously registered; reusing one actor instance across two traders or a trader restart without constructing a new actor.
Common situations: Building a second strategy/trader in the same process and accidentally sharing an actor; retrying registration after a failure; running a backtest twice with cached actor instances.
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
- DataActor {actor_id} registration incomplete - validation fa
- Actor {actor_id} has not been registered with a Trader
- Cannot add actor while node is running, add actors before ru
- Actor {actor_id} is already registered
- Failed to extract PyDataActor: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ec169c7c624764f2.
Report an issue: GitHub.