nautechsystems/nautilus_trader · error

Execution algorithm '{exec_algorithm_id}' is already registe

Error message

Execution algorithm '{exec_algorithm_id}' is already registered

What it means

Thrown by `add_py_execution_algorithm_instance` when an ExecAlgorithmId matching `algorithm.exec_algorithm_id()` is already present in the trader's `exec_algorithm_ids`. Exec algorithm IDs must be unique per trader so order routing can dispatch to the right algorithm. The same-ID check deliberately runs before the shared component-ID guard so same-kind duplicates get this specific message.

Source

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

    /// Adds a constructed [`PyExecutionAlgorithm`] instance to the trader.
    ///
    /// `wrapper` is the Python object which owns `algorithm`; the trader's registries keep it
    /// alive for as long as the algorithm stays registered.
    ///
    /// # Errors
    ///
    /// Returns an error if the trader already tracks a component under the algorithm's ID, or if
    /// the algorithm cannot be registered or tracked.
    pub fn add_py_execution_algorithm_instance(
        &mut self,
        algorithm: PyExecutionAlgorithm,
        wrapper: &Py<PyAny>,
    ) -> anyhow::Result<ExecAlgorithmId> {
        let exec_algorithm_id = algorithm.exec_algorithm_id();

        // Checked before the shared guard so a same-kind duplicate keeps its own message
        if self.exec_algorithm_ids.contains(&exec_algorithm_id) {
            anyhow::bail!("Execution algorithm '{exec_algorithm_id}' is already registered");
        }

        let component_id = ComponentId::from(exec_algorithm_id);
        self.ensure_component_id_available(component_id)?;

        if let Err(e) = self.add_exec_algorithm(algorithm) {
            // Without this the guard sees the stranded clock and dead-ends this ID until disposal
            self.release_component(component_id);
            return Err(e);
        }

        Python::attach(|py| {
            retain_python_wrapper(component_id, wrapper.clone_ref(py));
        });

        Ok(exec_algorithm_id)
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Give each exec algorithm a unique name/ID in its configuration
  2. Remove the duplicate registration call
  3. Check `trader.exec_algorithm_ids` before adding
  4. If re-registering, deregister the existing algorithm first

Example fix

// before
trader.add_exec_algorithm(algo_a);  # id: MyExecAlgorithm
trader.add_exec_algorithm(algo_a_clone);  # same id -> error
// after
algo_b = MyExecAlgorithm(config with name='MyExecAlgorithm2')
trader.add_exec_algorithm(algo_b);
Defensive patterns

Strategy: validation

Validate before calling

if exec_algorithm_id in trader.exec_algorithm_ids():
    raise ValueError(f"{exec_algorithm_id} already registered")

Type guard

def is_new_exec_algorithm(trader, algo) -> bool:
    return algo.exec_algorithm_id() not in trader.exec_algorithm_ids()

Try / catch

try:
    trader.add_exec_algorithm(algo)
except ValueError as e:
    if "already registered" in str(e):
        logger.warning("skipping duplicate exec algorithm: %s", e)
    else:
        raise

Prevention

When it happens

Trigger: Calling `add_py_execution_algorithm_instance` with a wrapper whose exec_algorithm_id was already registered — e.g. adding the same exec algorithm class twice, or two wrappers configured with the same name/ID.

Common situations: Duplicate exec_algorithm entries in a trader config; re-adding an algorithm after reconfiguration without deregistering; a test that registers the same algorithm twice (the listed caller is a test asserting ID reusability after failed registration).

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