nautechsystems/nautilus_trader · error

Venue {venue} already routed to {existing_client_id}, cannot

Error message

Venue {venue} already routed to {existing_client_id}, cannot register {client_id} for the same venue

What it means

The execution engine maintains a routing_map that maps each Venue to exactly one client ID. This error is raised during register_client when the venue is already routed to a different client, because a second client cannot be registered for the same venue — order routing would be ambiguous.

Source

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

    }

    /// 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.
    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);

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Deregister the existing client with deregister_client first (it also removes its routing_map entries), then register the new client.
  2. Register the second client with a distinct venue so each venue maps to one client.
  3. If the same client should own the venue, check register_client's idempotency: if the existing routed client_id equals the new client_id, no error occurs only via register_venue_routing; otherwise reuse the already-registered client.
  4. Inspect self.routing_map (or call the engine's lookup APIs) before registering to confirm the venue is unclaimed.

Example fix

// before
engine.register_client(client_b)?; // panics/bails: venue already routed to client_a
// after
engine.deregister_client(client_a_id)?;
engine.register_client(client_b)?;
Defensive patterns

Strategy: validation

Validate before calling

if engine.routing_target(&venue).is_some() {
    // venue already claimed: deregister existing client or pick another venue
}

Try / catch

match engine.register_client(client) {
    Err(e) if e.to_string().contains("already routed") => log::warn!("venue already claimed, skipping: {e}"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling ExecutionEngine::register_client with an ExecutionClient whose venue is already present in the engine's routing_map pointing at another client ID. In tests it is hit when registering a second client for the same venue (e.g. dual hedge legs across clients in reconciliation scenarios).

Common situations: Configuring two execution clients (e.g. two accounts or a live+test setup) that both resolve to the same Venue; re-registering a client under a new ID after the old one is still routed; a reconciliation test registering both hedge legs whose clients share a venue.

Related errors


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