nautechsystems/nautilus_trader · error

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

Error message

Venue {venue} already routed to {existing_client_id}, cannot re-route to {client_id}

What it means

A Venue can be routed to only one client. register_venue_routing refuses to overwrite an existing routing entry when the new ClientId differs from the one already mapped to that Venue, bailing with this message. Re-registering the same client for the same venue is idempotent and allowed.

Source

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

    /// 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,
        client_id: ClientId,
        venue: Venue,
    ) -> anyhow::Result<()> {
        if !self.clients.contains_key(&client_id) {
            anyhow::bail!("No client registered with ID {client_id}");
        }

        if let Some(existing_client_id) = self.routing_map.get(&venue)
            && *existing_client_id != client_id
        {
            anyhow::bail!(
                "Venue {venue} already routed to {existing_client_id}, \
                 cannot re-route to {client_id}"
            );
        }

        self.routing_map.insert(venue, client_id);
        log::debug!("Set client {client_id} routing for {venue}");
        Ok(())
    }

    /// Starts all registered data clients and re-arms bar aggregator timers.
    pub fn start(&mut self) {
        for client in self.get_clients_mut() {
            if let Err(e) = client.start() {
                log::error!("{e}");
            }
        }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Remove the conflicting routing registration so only one client maps to the venue.
  2. If re-routing is intended, clear/replace the existing routing map entry via the engine's API instead of double-registering.
  3. Deduplicate config so each venue appears in the routing section only once.

Example fix

// before
engine.register_venue_routing(ClientId::from("Bybit"), venue)?; // venue already routed to Binance
// after
// keep exactly one routing entry per venue
engine.register_venue_routing(ClientId::from("Binance"), venue)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust
// detect duplicate venue routing before registering
if let Some(existing) = planned_routing.get(&venue) {
    if existing != &client_id {
        return Err(format!("venue {venue} routed twice: {existing} and {client_id}"));
    }
}
planned_routing.insert(venue, client_id);
engine.register_venue_routing(client_id, venue)?;

Try / catch

// Rust
if let Err(e) = engine.register_venue_routing(client_id, venue) {
    if e.to_string().contains("already routed") {
        log::warn!("ignoring duplicate venue routing: {e}"); // treat re-route conflict as config bug
    } else {
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Calling register_venue_routing(client_id, venue) when routing_map already contains venue mapped to a different client_id — e.g. two registrations for the same venue from different config sections or different adapters claiming the same venue.

Common situations: Duplicate venue routing entries in a TOML/JSON config; two adapters both supporting the same venue both being routed; re-running registration code after the routing table was already populated.

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