nautechsystems/nautilus_trader · error
default client already registered
Error message
default client already registered
What it means
The engine supports at most one default execution client. set_default_client bails with this error if default_client_id is already Some, since reassigning the default client is not allowed through this API.
Source
Thrown at crates/execution/src/engine/mod.rs:396
/// Registers a default execution client for fallback routing.
pub fn register_default_client(&mut self, client: Box<dyn ExecutionClient>) {
let client_id = client.client_id();
let adapter = ExecutionClientAdapter::new(client);
self.clients.insert(client_id, adapter);
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 default
/// client has already been set.
pub fn set_default_client(&mut self, client_id: ClientId) -> anyhow::Result<()> {
if self.default_client_id.is_some() {
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(())
}
#[must_use]
/// Returns a reference to the execution client registered with the given ID.
pub fn get_client(&self, client_id: &ClientId) -> Option<&dyn ExecutionClient> {
self.clients.get(client_id).map(|a| a.client.as_ref())
}
#[must_use]
/// Returns a mutable reference to the execution client adapter registered with the given ID.View on GitHub (pinned to 18893faf8b)
Solutions
- Call set_default_client only once per engine instance, before any other default assignment.
- If replacement is intended, call deregister_client with the current default's client ID first (tests show deregistering the default clears default_client_id), then set the new default.
- Guard the call: only invoke set_default_client when no default has been set yet.
Example fix
// before engine.set_default_client(default_id)?; engine.set_default_client(new_default_id)?; // bails // after engine.set_default_client(default_id)?; engine.deregister_client(default_id)?; engine.set_default_client(new_default_id)?;
Defensive patterns
Strategy: validation
Validate before calling
// set the default exactly once during engine construction, before any other setup runs
Try / catch
match engine.set_default_client(id) {
Err(e) if e.to_string().contains("default client already registered") => {} // keep existing default
other => other?,
} Prevention
- Assign the default client in exactly one place in your startup code.
- Never call set_default_client in shared fixtures without resetting/rebuilding the engine.
- To replace a default, deregister the current default first.
When it happens
Trigger: Calling ExecutionEngine::set_default_client after a default client has already been set in the engine's lifetime (default_client_id.is_some() == true).
Common situations: Calling set_default_client twice during node startup (e.g. config-driven setup plus programmatic setup); replacing a default client without first deregistering it; running a test fixture that calls set_default_client per test against a shared engine.
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
- Order for {} not found to determine position ID
- dYdX WebSocket stream task is already registered
- Client already registered with ID {client_id}
- Venue {venue} already routed to {existing_client_id}, cannot
- No client registered with ID {client_id}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/bdf984c65aa9a2c6.
Report an issue: GitHub.