nautechsystems/nautilus_trader · error

Cannot find contingent order for {client_order_id}

Error message

Cannot find contingent order for {client_order_id}

What it means

While validating contingent-order constraints, the engine matched a case where the linked (contingent) order's snapshot was None — i.e. the order referenced via linked_order_ids is not in the cache — and panicked instead of continuing validation. An order that participates in a contingency chain must exist locally; its absence means broken chain state. The panic guards against silently mis-validating OCO/OTO relationships.

Source

Thrown at crates/execution/src/matching_engine/mod.rs:2876

                }

                if let Some(linked_order_ids) = order.linked_order_ids() {
                    let contingency_type = order.contingency_type();
                    for client_order_id in linked_order_ids {
                        match cache_borrow.order(client_order_id) {
                            Some(contingent_order)
                                if matches!(
                                    contingency_type,
                                    Some(ContingencyType::Oco | ContingencyType::Ouo)
                                ) && !order.is_closed()
                                    && contingent_order.is_closed() =>
                            {
                                break 'validate Some(
                                    format!("Contingent order {client_order_id} already closed")
                                        .into(),
                                );
                            }
                            None => panic!("Cannot find contingent order for {client_order_id}"),
                            _ => {}
                        }
                    }
                }
            }

            // Check for valid order quantity precision
            if order.quantity().precision != self.instrument.size_precision() {
                break 'validate Some(
                    format!(
                        "Invalid order quantity precision for order {}, was {} when {} size precision is {}",
                        order.client_order_id(),
                        order.quantity().precision,
                        self.instrument.id(),
                        self.instrument.size_precision()
                    )
                    .into(),
                );

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure every order in linked_order_ids is submitted/cached on the same node that validates the chain.
  2. Enable cache persistence so contingent chains survive restarts, or rebuild links during reconciliation.
  3. Filter out orders whose linked orders cannot be resolved before dispatching them to the matching engine.
  4. Avoid evicting/finalizing one member of a chain while siblings are still being validated; update the whole chain atomically.

Example fix

// before
order.linked_order_ids = Some(vec![missing_order_id]);
// after
let linked = linked_ids.into_iter().filter(|id| cache.order(id).is_some()).collect::<Vec<_>>();
order.linked_order_ids = (!linked.is_empty()).then_some(linked);
Defensive patterns

Strategy: validation

Validate before calling

let linked = order.linked_order_ids().unwrap_or_default();
let all_cached = linked.iter().all(|id| engine.order_snapshot(id).is_some());
if !all_cached { return Err(anyhow!("contingent chain incomplete")); }

Type guard

fn chain_complete(engine: &OrderMatchingEngine, order: &OrderAny) -> bool {
    order.linked_order_ids().map_or(true, |ids| ids.iter().all(|id| engine.order_snapshot(id).is_some()))
}

Prevention

When it happens

Trigger: Validating an order whose linked_order_ids contains a client_order_id with no entry in the matching-engine cache (order_snapshot returns None) during contingency checks.

Common situations: OCO/OTO chains built on a different node or lost by a cache restart; cancel/replace races where the linked order was already finalized and evicted; adapters replaying orders with stale linked_order_ids.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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