nautechsystems/nautilus_trader · error

default client already registered

Error message

default client already registered

What it means

`set_default_client` designates a registered client as the engine's default. This error fires when a different client is already registered as the default — the engine enforces a single default client and refuses to silently replace it. (A second error path in the same method reports an unknown client_id.)

Source

Thrown at crates/data/src/engine/mod.rs:520

            "default client already registered",
        )
        .expect(FAILED);

        let client_id = client.client_id();
        self.clients.insert(client_id, client);
        self.default_client_id = Some(client_id);
        log::debug!("Registered default client {client_id}");
    }

    /// Marks an already-registered client as the default for fallback routing.
    ///
    /// # Errors
    ///
    /// Returns an error if no client is registered with the given ID, or a different
    /// client is already the default.
    pub fn set_default_client(&mut self, client_id: ClientId) -> anyhow::Result<()> {
        if self.default_client_id.is_some_and(|id| id != client_id) {
            anyhow::bail!("default client already registered");
        }

        if !self.clients.contains_key(&client_id) {
            anyhow::bail!("No client registered with ID {client_id}");
        }
        self.default_client_id = Some(client_id);
        log::debug!("Set client {client_id} as default");
        Ok(())
    }

    /// Sets routing for a specific venue to a given client ID.
    ///
    /// # Errors
    ///
    /// Returns an error if the client ID is not registered, or the venue is already routed to a
    /// different client.
    pub fn register_venue_routing(
        &mut self,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check `default_client_id` before calling, or only set the default once during initialization
  2. If replacement is intended, explicitly unset/replace the default via the appropriate API rather than re-setting
  3. Deduplicate initialization logic so competing components don't both set the default
  4. Catch and ignore this error when the intent is 'ensure a default exists' and one is already set

Example fix

// before
engine.set_default_client(client_id)?; // may conflict on re-init
// after
if engine.default_client_id() != Some(client_id) {
    engine.set_default_client(client_id)?;
}
Defensive patterns

Strategy: try-catch

Validate before calling

if engine.default_client_id().is_some() && engine.default_client_id() != Some(client_id) {
    // decide: keep existing default or explicitly replace via the proper path
} else {
    engine.set_default_client(client_id)?;
}

Try / catch

if let Err(e) = engine.set_default_client(client_id) {
    if e.to_string().contains("already registered") {
        tracing::debug!("default client already set; ignoring");
    } else {
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Calling `set_default_client(id_b)` after `set_default_client(id_a)` succeeded, where id_b != id_a. Calling with the currently-default id succeeds (no-op reassignment).

Common situations: Initialization code paths running twice and re-attempting default-client setup; multiple components each trying to install their preferred default; config reloading that re-runs registration without checking current state.

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


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