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
- Fix the adapter so every report for a venue_order_id carries the same client_order_id that was used to submit the order
- Clear/purge stale cache entries and re-reconcile so the venue order mapping is rebuilt from the venue
- Check for venue_order_id collisions (e.g. exchange reusing IDs across sessions) and include a session/epoch component in IDs
- 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
- Always reuse the submission-time client_order_id in every report the adapter emits
- Key reports by venue_order_id, not by a per-report generated ID
- Test adapters with reconciliation replay to catch ID drift early
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
- fill {} order side or venue order ID differs from cached ord
- fill {} position ID {venue_position_id} conflicts with cache
- fill {} maps to position {position_id}, which is not cached
- fill {} maps to position {position_id} with a different acco
- fill {} maps to non-open position {position_id}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/06283d7dc9a2ce2b.
Report an issue: GitHub.