nautechsystems/nautilus_trader · error · anyhow::Error

Order {client_order_id} is already claimed by execution clie

Error message

Order {client_order_id} is already claimed by execution client {existing_client_id} and cannot be claimed by {client_id}

What it means

A single execution-client claim fails because `index.order_client` already maps the client_order_id to a different ClientId. Only one execution client may own an order; claiming by a second client is rejected. Claims already consistent with the existing owner are no-ops, and unclaimed orders are queued into pending_claims.

Source

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

                    );
                }
                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) {
                Some(existing_client_id) if *existing_client_id == client_id => {}
                Some(existing_client_id) => {
                    anyhow::bail!(
                        "Order {client_order_id} is already claimed by execution client \
                         {existing_client_id} and cannot be claimed by {client_id}"
                    );
                }
                None => pending_claims.push((client_order_id, client_id)),
            }
        }

        if pending_claims.is_empty() {
            return Ok(());
        }

        if let Some(database) = &self.database {
            database.index_order_clients(&pending_claims)?;
        }

        for (client_order_id, client_id) in pending_claims {
            self.index.order_client.insert(client_order_id, client_id);

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use the existing owner client for that order (check the index before claiming).
  2. Restore the original ClientId in config so it matches the persisted claims.
  3. If ownership must move, release the existing claim via the intended cache path, then re-claim.
Defensive patterns

Strategy: validation

Validate before calling

if let Some(owner) = cache.exec_client_id_for(&client_order_id) {
    if owner != client_id { /* use the owning client or release the claim first */ }
}

Prevention

When it happens

Trigger: Calling the claim API for an order already claimed by another execution client; reconfiguring an exec client that previously owned orders from a prior session with a different ClientId; reconciliation handing the same order to two clients.

Common situations: Changing the exec client's ID in config between runs while reusing persistent order indexes; multiple adapters subscribed to overlapping venues; test setups sharing a cache across client fixtures.

Related errors


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