nautechsystems/nautilus_trader · error

Component {component_id} is already registered with trader {

Error message

Component {component_id} is already registered with trader {}

What it means

The generic component-ID collision guard: thrown when the ComponentId (actor, strategy, or exec algorithm) you are registering is already tracked by this trader under any of `actor_ids`, `strategy_ids`, or `exec_algorithm_ids`. It prevents cross-kind ID collisions where, say, an actor and a strategy share the same identifier, which would break component lookup and message routing.

Source

Thrown at crates/system/src/python/registration.rs:476

    /// live strategy would overwrite that strategy's clock, registry entries, and wrapper, and a
    /// rollback would then remove state the attempt did not create. The lifecycle collections are
    /// checked alongside the clocks because a component registered externally and tracked through
    /// `add_*_id_for_lifecycle` has no trader-owned clock.
    fn ensure_component_id_available(&self, component_id: ComponentId) -> anyhow::Result<()> {
        let id = component_id.inner();
        let tracked = self.clocks.contains_key(&component_id)
            || self.actor_ids.iter().any(|actor_id| actor_id.inner() == id)
            || self
                .strategy_ids
                .iter()
                .any(|strategy_id| strategy_id.inner() == id)
            || self
                .exec_algorithm_ids
                .iter()
                .any(|exec_algorithm_id| exec_algorithm_id.inner() == id);

        if tracked {
            anyhow::bail!(
                "Component {component_id} is already registered with trader {}",
                self.trader_id
            );
        }

        Ok(())
    }
}

fn create_python_actor(config: &ImportableActorConfig) -> anyhow::Result<(Py<PyAny>, ActorId)> {
    let (module_name, class_name) = split_import_path(&config.actor_path, "actor_path")?;

    log::info!("Importing actor from module: {module_name} class: {class_name}");

    Python::attach(|py| -> anyhow::Result<(Py<PyAny>, ActorId)> {
        let actor_class = import_python_class(py, module_name, class_name)?;
        let config_instance = create_config_instance(py, &config.config_path, &config.config)?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Rename the conflicting component so each ComponentId is globally unique on the trader
  2. Inspect `trader_id` and the existing ID sets to find the colliding component
  3. Move the component to a different trader instance if both registrations are intentional
  4. Consolidate duplicate config entries sharing one name

Example fix

// before
ActorConfig { name: 'Alpha' }      // actor
StrategyConfig { name: 'Alpha' }   // strategy -> ComponentId collision
// after
StrategyConfig { name: 'AlphaStrategy' }
Defensive patterns

Strategy: validation

Validate before calling

all_ids = trader.actor_ids() + trader.strategy_ids() + trader.exec_algorithm_ids()
ids = [c.value for c in all_ids]
assert len(ids) == len(set(ids)), f"duplicate component ids: {ids}"

Type guard

def component_id_is_free(trader, component_id) -> bool:
    return component_id.value not in (
        {c.value for c in trader.actor_ids()} |
        {c.value for c in trader.strategy_ids()} |
        {c.value for c in trader.exec_algorithm_ids()}
    )

Try / catch

try:
    trader.add_actor(actor)
except ValueError as e:
    if "already registered with trader" in str(e):
        raise ConfigError(f"component name collision: {e}") from e
    else:
        raise

Prevention

When it happens

Trigger: Calling add_python_actor_instance, prepare/commit_python_strategy_instance, or add_py/python_exec_algorithm_instance with a component whose ID equals an existing component of ANY kind on the trader (the same-kind duplicates get their own messages first; this fires for cross-kind collisions or after those checks pass).

Common situations: An actor named 'MyStrategy-001' colliding with a strategy ID; config files that reuse the same component name across actor/strategy/exec-algorithm sections; migrating components between kinds without renaming.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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