nautechsystems/nautilus_trader · error · anyhow::Error

venue position ID differs across fill group

Error message

venue position ID differs across fill group

What it means

A synthesized OrderStatusReport for an orphan fill group must resolve to one position. This ensure! checks that all fills in the group report the same venue_position_id (earlier code already bail!s if it is missing entirely); differing position IDs mean the group spans multiple positions and cannot be aggregated into one order report.

Solutions

  1. Ensure the adapter's account configuration (netting vs hedging) matches the actual venue account mode so fills map to a single position ID per order.
  2. Group fills by venue_position_id as part of the key so each group has one consistent position ID.
  3. Check that venue_position_id is parsed from the venue's fill report rather than derived inconsistently per fill.
  4. Re-run reconciliation after correcting account mode / position ID derivation so stale groups are rebuilt from fresh venue reports.

Example fix

// before: group keyed without position
let key = (account_id, venue_order_id);
// after: require a single position ID per group
let key = (account_id, venue_order_id, fill.venue_position_id?);
Defensive patterns

Strategy: validation

Validate before calling

let pos_ids: std::collections::HashSet<_> = fills.iter().map(|f| f.venue_position_id).collect();
assert!(pos_ids.len() == 1 && pos_ids.iter().all(|p| p.is_some()), "fill group has missing or mixed venue position IDs: {:?}", pos_ids);

Type guard

fn single_position_group(fills: &[&FillReport]) -> bool {
    fills[0].venue_position_id.is_some()
        && fills.iter().all(|f| f.venue_position_id == fills[0].venue_position_id)
}

Prevention

When it happens

Trigger: FillReports grouped together share order/account/instrument keys but their venue_position_id values differ — e.g. fills that were assigned to different OMS positions by the venue, or None vs Some mismatches that slipped past grouping.

Common situations: Netting vs hedging account-mode mismatches between the venue account and the Nautilus reconciliation config; venue splitting one order's fills across positions after account mode changes; adapter changes to position-ID derivation between versions.

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/02173d92ce5730cf. Report an issue: GitHub.

Appendix: source

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

                "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!(
            first.instrument_id == instrument.id(),
            "instrument metadata does not match fill group"
        );

        let (quantity, notional) = fills.iter().try_fold(
            (Decimal::ZERO, Decimal::ZERO),
            |(quantity, notional), fill| {
                let fill_quantity = fill.last_qty.as_decimal();
                let quantity = quantity.checked_add(fill_quantity).ok_or_else(|| {
                    anyhow::anyhow!("fill quantity overflow while aggregating fill group")
                })?;

View on GitHub (pinned to 18893faf8b)