nautechsystems/nautilus_trader · error · anyhow::Error

Conflicting execution client claims for {client_order_id}: {

Error message

Conflicting execution client claims for {client_order_id}: {existing_client_id} and {client_id}

What it means

During batched execution-client claim registration, the same client_order_id appears twice in the claims list with two different ClientIds. The method builds an intermediate map and refuses inconsistent claims before any state is mutated, keeping the batch atomic.

Source

Thrown at crates/common/src/cache/mod.rs:4848

    /// claim is idempotent, and a conflicting claim is rejected. The complete batch is validated
    /// and its persistence command is successfully enqueued before any in-memory index is
    /// changed.
    ///
    /// # Errors
    ///
    /// Returns an error if an order is not cached, an order is already claimed by another client,
    /// the same order has conflicting claims in the batch, or persistence cannot be enqueued.
    pub fn claim_order_clients(
        &mut self,
        claims: &[(ClientOrderId, ClientId)],
    ) -> anyhow::Result<()> {
        let mut requested = AHashMap::with_capacity(claims.len());
        let mut ordered_claims = Vec::with_capacity(claims.len());

        for (client_order_id, client_id) in claims {
            if let Some(existing_client_id) = requested.get(client_order_id) {
                if existing_client_id != client_id {
                    anyhow::bail!(
                        "Conflicting execution client claims for {client_order_id}: \
                         {existing_client_id} and {client_id}"
                    );
                }
                continue;
            }

            requested.insert(*client_order_id, *client_id);
            ordered_claims.push((*client_order_id, *client_id));
        }

        let mut pending_claims = Vec::with_capacity(ordered_claims.len());
        for (client_order_id, client_id) in ordered_claims {
            if !self.orders.contains_key(&client_order_id) {
                return Err(OrderLookupError::not_found(client_order_id).into());
            }

            match self.index.order_client.get(&client_order_id) {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Deduplicate/merge the claims list so each client_order_id appears once with a single ClientId.
  2. Fix the source that assigns the wrong client for that order.
  3. If the batch comes from config, make client routing deterministic for each order.
Defensive patterns

Strategy: validation

Validate before calling

let mut seen: AHashMap<ClientOrderId, ClientId> = AHashMap::default();
for (coid, cid) in &claims {
    if let Some(prev) = seen.get(coid) {
        if prev != cid { /* resolve conflict before batch registration */ }
    } else { seen.insert(coid.clone(), cid.clone()); }
}

Prevention

When it happens

Trigger: Calling `add_execution_client_claims`-style registration with a claims list containing the same client_order_id mapped to different clients; building the list from two sources (e.g. config + reconciliation) that disagree on ownership.

Common situations: Merging claim lists from multiple execution clients after reconnect; a config error routing one order to two clients; adapter reconciliation producing overlapping claim sets.

Related errors


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