nautechsystems/nautilus_trader · error · anyhow::Error

fill {} client order ID {report_client_order_id} conflicts w

Error message

fill {} client order ID {report_client_order_id} conflicts with venue order mapping {venue_client_order_id}

What it means

During preparation of a PositionFillReport in the live execution manager, the fill report's client_order_id is checked against the venue-order-ID to client-order-ID mapping cached for the venue_order_id. If both exist and differ, the fill contradicts the venue's own order mapping, indicating corrupted or mismatched report data, so the manager fails fast with anyhow::ensure!.

Source

Thrown at crates/live/src/execution/manager.rs:2825

    ) -> bool {
        check
            .activity_revisions
            .get(key)
            .is_some_and(|revision| self.position_activity_revision(key) == *revision)
    }

    #[cfg(feature = "node")]
    pub(crate) fn prepare_position_fill_report(
        &self,
        report: &mut FillReport,
        venue_reports: &[PositionStatusReport],
    ) -> anyhow::Result<PositionFillReportPreparation> {
        let cache = self.cache.borrow();
        let venue_client_order_id = cache.client_order_id(&report.venue_order_id).copied();
        if let (Some(report_client_order_id), Some(venue_client_order_id)) =
            (report.client_order_id, venue_client_order_id)
        {
            anyhow::ensure!(
                report_client_order_id == venue_client_order_id,
                "fill {} client order ID {report_client_order_id} conflicts with venue order mapping {venue_client_order_id}",
                report.trade_id,
            );
        }
        let client_order_id = report.client_order_id.or(venue_client_order_id);
        let order = client_order_id.and_then(|id| cache.order(&id));
        if let Some(order) = &order {
            anyhow::ensure!(
                order.instrument_id() == report.instrument_id
                    && order.order_side() == report.order_side
                    && order
                        .account_id()
                        .is_none_or(|account_id| account_id == report.account_id)
                    && order
                        .venue_order_id()
                        .is_none_or(|venue_order_id| venue_order_id == report.venue_order_id),
                "fill {} conflicts with cached order {}",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Fix the adapter so every report for a venue_order_id carries the same client_order_id that was used to submit the order
  2. Clear/purge stale cache entries and re-reconcile so the venue order mapping is rebuilt from the venue
  3. Check for venue_order_id collisions (e.g. exchange reusing IDs across sessions) and include a session/epoch component in IDs
  4. Ensure reports are processed in order and cache is not cleared between order submission and fills

Example fix

// before (adapter builds report with fresh ID)
report.client_order_id = Some(ClientOrderId::new(format!("{}-fill", venue_order_id)));
// after (reuse the ID registered at submission)
report.client_order_id = self.submitted_client_order_id(&report.venue_order_id);
Defensive patterns

Strategy: validation

Validate before calling

if let (Some(coid), Some(vpid)) = (report.client_order_id, cache.client_order_id(&report.venue_order_id)) {
    debug_assert_eq!(coid, vpid, "fill client_order_id diverges from venue mapping");
}

Type guard

fn mapping_consistent(report: &TradeReport, cache: &Cache) -> bool {
    cache.client_order_id(&report.venue_order_id)
        .map_or(true, |mapped| report.client_order_id.map_or(true, |c| c == mapped))
}

Prevention

When it happens

Trigger: An execution/fill report (TradeReport) arrives whose venue_order_id maps to client_order_id X in the cache, but the report itself carries client_order_id Y (Y != X). Typically caused by an adapter generating a new client order ID per report, duplicated venue_order_id across orders, or stale cache after restart.

Common situations: Custom broker/venue adapter implementations that mint fresh client_order_ids in fill reports; running a live node against a reused venue_order_id; a reconciler replaying old reports after a client_order_id scheme change or venue order amendment.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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