nautechsystems/nautilus_trader · error

Client already registered with ID {client_id}

Error message

Client already registered with ID {client_id}

What it means

ExecutionEngine.register_client refuses to register a second ExecutionClient whose ClientId already exists in self.clients. Client IDs must be unique within the engine; the duplicate is rejected before any routing map is touched.

Source

Thrown at crates/execution/src/engine/mod.rs:360

    }

    #[must_use]
    /// Returns any external order claim for the given instrument ID.
    pub fn get_external_order_claim(&self, instrument_id: &InstrumentId) -> Option<StrategyId> {
        self.cache.borrow().external_order_claim(instrument_id)
    }

    /// Registers a new execution client.
    ///
    /// # Errors
    ///
    /// Returns an error if a client with the same ID is already registered.
    pub fn register_client(&mut self, client: Box<dyn ExecutionClient>) -> anyhow::Result<()> {
        let client_id = client.client_id();
        let venue = client.venue();

        if self.clients.contains_key(&client_id) {
            anyhow::bail!("Client already registered with ID {client_id}");
        }

        let adapter = ExecutionClientAdapter::new(client);

        if let Some(existing_client_id) = self.routing_map.get(&venue) {
            anyhow::bail!(
                "Venue {venue} already routed to {existing_client_id}, \
                 cannot register {client_id} for the same venue"
            );
        }

        self.routing_map.insert(venue, client_id);
        log::debug!("Registered client {client_id}");
        self.clients.insert(client_id, adapter);
        Ok(())
    }

    /// Registers a default execution client for fallback routing.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure each client has a unique ClientId before registration
  2. Check contains/lookup before registering, or reuse the existing registered client
  3. Fix the config so the same adapter is not instantiated twice

Example fix

// before
engine.register_client(client_a.clone())?;
engine.register_client(client_a)?; // duplicate ClientId
// after
if !engine.clients_registered().contains(&client_a.client_id()) {
    engine.register_client(client_a)?;
}
Defensive patterns

Strategy: validation

Validate before calling

if engine.registered_client_ids().contains(&client.client_id()) {
    return Err(anyhow!("duplicate client {}", client.client_id()));
}

Try / catch

match engine.register_client(client) {
    Err(e) if e.to_string().contains("already registered") => {/* reuse existing client */},
    other => other?,
}

Prevention

When it happens

Trigger: Calling register_client twice with clients reporting the same client_id() — e.g. constructing two adapters for the same venue/client and registering both at startup.

Common situations: Duplicate adapter instantiation in a live-trading config (same client id configured twice); test setups re-registering a fixture client; a retry path that re-registers instead of reusing the existing client.

Related errors


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