nautechsystems/nautilus_trader · error · anyhow::Error
venue order ID differs across fill group
Error message
venue order ID differs across fill group
What it means
During reconciliation, NautilusTrader groups multiple FillReports that belong to the same external (orphan) order and synthesizes a single OrderStatusReport from them via create_orphan_fill_order_report. This ensure! guards the invariant that every fill in the group carries the same venue_order_id; a group whose fills disagree cannot be collapsed into one order report. It is an internal consistency check on venue-reported fill data.
Source
Thrown at crates/live/src/execution/manager.rs:1283
instrument: &InstrumentAny,
) -> anyhow::Result<OrderStatusReport> {
let Some(first) = fills.first() else {
anyhow::bail!("fill group is empty");
};
let venue_position_id = first
.venue_position_id
.ok_or_else(|| anyhow::anyhow!("venue position ID is missing"))?;
for fill in fills.iter().skip(1) {
anyhow::ensure!(
fill.account_id == first.account_id,
"account ID differs across fill group"
);
anyhow::ensure!(
fill.instrument_id == first.instrument_id,
"instrument ID differs across fill group"
);
anyhow::ensure!(
fill.venue_order_id == first.venue_order_id,
"venue order ID differs across fill group"
);
anyhow::ensure!(
fill.client_order_id == first.client_order_id,
"client order ID differs across fill group"
);
anyhow::ensure!(
fill.order_side == first.order_side,
"order side differs across fill group"
);
anyhow::ensure!(
fill.venue_position_id == first.venue_position_id,
"venue position ID differs across fill group"
);
}
anyhow::ensure!(View on GitHub (pinned to 18893faf8b)
Solutions
- Check how your venue adapter keys fill groups during reconciliation; fills must be grouped by (account_id, instrument_id, venue_order_id) before reaching create_orphan_fill_order_report.
- Inspect the FillReport data from the venue's order/mass status report and verify venue_order_id is populated consistently for all fills of the same order.
- Update or pin the adapter crate version so its grouping logic matches the venue's current ID semantics.
- If the fills genuinely belong to different orders, ensure they are split into separate groups (or that one is not mislabeled as an orphan fill) instead of merged.
Example fix
// before: grouping fills by position only let group: Vec<&FillReport> = fills_by_position[position_id].clone(); // after: group by venue order ID as well let group: Vec<&FillReport> = fills_by_order[&venue_order_id].clone();
Defensive patterns
Strategy: validation
Validate before calling
let venue_order_ids: std::collections::HashSet<_> = fills.iter().map(|f| f.venue_order_id).collect();
assert!(venue_order_ids.len() == 1, "fill group spans multiple venue order IDs: {:?}", venue_order_ids); Type guard
fn single_venue_order_group(fills: &[&FillReport]) -> bool {
fills.iter().all(|f| f.venue_order_id == fills[0].venue_order_id)
} Prevention
- Always key reconciliation fill groups by (account_id, instrument_id, venue_order_id).
- Log venue_order_id for every FillReport received so mis-grouping is visible before aggregation.
- Keep venue adapter versions in sync with the deployed venue API semantics.
When it happens
Trigger: A batch of FillReports passed to create_orphan_fill_order_report (built during generate_order_status_reports / reconciliation from mass status fill reports) contains two fills with identical instrument/account/position grouping keys but different venue_order_id values, so the deduplication keying used to form the group did not match the fills' actual venue_order_id.
Common situations: Venue adapter bugs in fill-report grouping (e.g. grouping by trade ID or position instead of venue order ID); adapter updates after a venue changed its order-ID semantics; manually constructed or replayed reconciliation payloads mixing fills from different orders.
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
- client order ID differs across fill group
- order side differs across fill group
- venue position ID differs across fill group
- Binance Futures position request has unresolved instrument {
- Modify order failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e00c3ecd89376322.
Report an issue: GitHub.