nautechsystems/nautilus_trader · error · anyhow::Error
fill {} position ID {venue_position_id} conflicts with cache
Error message
fill {} position ID {venue_position_id} conflicts with cached order position {mapped_position_id} What it means
In hedge mode (hedging context), a fill report's venue_position_id is compared to the position ID mapped to the cached order. If they differ, the fill is attributed to a different position than the order's mapping, so the manager rejects it to keep position hedging consistent.
Source
Thrown at crates/live/src/execution/manager.rs:2861
"fill {} conflicts with cached order {}",
report.trade_id,
order.client_order_id(),
);
}
let hedge_context = report.venue_position_id.is_some()
|| venue_reports
.iter()
.any(|venue_report| venue_report.venue_position_id.is_some());
let mapped_position_id = client_order_id
.and_then(|client_order_id| cache.position_id(&client_order_id))
.copied();
if hedge_context
&& let (Some(venue_position_id), Some(mapped_position_id)) =
(report.venue_position_id, mapped_position_id)
{
anyhow::ensure!(
venue_position_id == mapped_position_id,
"fill {} position ID {venue_position_id} conflicts with cached order position {mapped_position_id}",
report.trade_id,
);
}
if let Some(order) = order
&& Self::has_active_inferred_fill(&order)?
{
return Ok(PositionFillReportPreparation::InferredOverlap);
}
if !hedge_context {
return Ok(PositionFillReportPreparation::Ready);
}
if report.venue_position_id.is_some() {
return Ok(PositionFillReportPreparation::Ready);View on GitHub (pinned to 18893faf8b)
Solutions
- Make the adapter return the venue_position_id consistently for all fills of the same position
- Verify the node is configured with the correct netting vs hedging account type matching the venue
- Re-reconcile cached position mappings with venue state after reconnects
- Purge stale cache entries whose position mappings no longer match the venue
Example fix
// before (synthetic per-fill position ID) report.venue_position_id = Some(VenuePositionId::new(uuid::Uuid::new_v4().to_string())); // after (venue-reported position, reused across fills) report.venue_position_id = venue_fill.position_id.map(VenuePositionId::from);
Defensive patterns
Strategy: validation
Validate before calling
if hedge_context {
if let (Some(vp), Some(mp)) = (report.venue_position_id, cache.mapped_position_id(&client_order_id)) {
assert_eq!(vp, mp);
}
} Type guard
fn position_mapping_consistent(report: &TradeReport, order: &OrderAny) -> bool {
report.venue_position_id.map_or(true, |p| {
order.position_id().map_or(true, |op| op == p)
})
} Prevention
- Configure netting vs hedging account type to match the venue's real behavior
- Reconcile position mappings after every reconnect
- Never synthesize position IDs per fill; always propagate the venue's ID
When it happens
Trigger: A fill arrives with venue_position_id P1 while the cached order's position mapping says P2, under a hedging account. Happens when the venue reassigns positions, when the adapter invents position IDs per fill, or when cache position mappings are stale after restart/reconciliation.
Common situations: Hedging mode with venues that aggregate fills into positions differently than the adapter assumed; netting venue behind a hedging-configured node; adapter generating synthetic position IDs that drift from cached ones.
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 {} maps to position {position_id} with a different acco
- Position id should be generated. Hedging Oms type order matc
- fill {} client order ID {report_client_order_id} conflicts w
- fill {} order side or venue order ID differs from cached ord
- fill {} maps to position {position_id}, which is not cached
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/616bb289e2f1e3e6.
Report an issue: GitHub.