{"record":{"id":"9ca625ec50ea063d","repo":"nautechsystems/nautilus_trader","slug":"venue-leg-fills-are-negative","errorCode":null,"errorMessage":"venue-leg fills are negative","messagePattern":"venue-leg fills are negative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/reconciliation.rs","lineNumber":78,"sourceCode":"    order: &OrderAny,\n    venue_order_id: VenueOrderId,\n    size_precision: u8,\n) -> anyhow::Result<(Quantity, Quantity)> {\n    let mut filled = Decimal::ZERO;\n\n    for event in order.events() {\n        match event {\n            OrderEventAny::Filled(event) if event.venue_order_id == venue_order_id => {\n                filled += event.last_qty.as_decimal();\n            }\n            OrderEventAny::FillVoided(event) if event.venue_order_id == venue_order_id => {\n                filled -= event.voided_qty.as_decimal();\n            }\n            _ => {}\n        }\n    }\n\n    anyhow::ensure!(filled >= Decimal::ZERO, \"venue-leg fills are negative\");\n    let current_leg_filled = Quantity::from_decimal_dp(filled, size_precision)\n        .context(\"venue-leg fills exceed quantity precision\")?;\n    anyhow::ensure!(\n        current_leg_filled.as_decimal() == filled,\n        \"venue-leg fills cannot be represented exactly\"\n    );\n    let filled_before = order\n        .filled_qty()\n        .checked_sub(current_leg_filled)\n        .context(\"current venue-leg fills exceed cumulative fills\")?;\n    let leg_quantity = order\n        .quantity()\n        .checked_sub(filled_before)\n        .context(\"fills before current venue leg exceed logical quantity\")?;\n    Ok((filled_before, leg_quantity))\n}\n\n/// Shared context for trade-to-fill-report conversion.","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/reconciliation.rs#L60-L96","documentation":"venue_leg_filled_before_and_quantity reconstructs the venue-leg filled quantity by summing/adjusting event quantities (including subtracting voided_qty). If the resulting total is negative — impossible for a filled quantity — the invariant is violated and the function errors. This guards order-status reconstruction used by reconciliation and order reports.","triggerScenarios":"Replaying order events where a void/cancel adjustment exceeds the accumulated filled quantity — e.g. duplicate void events, out-of-order event application, or corrupt cache in load_orders_from_cache / query_order_command / generate_order_status_report(s)_impl.","commonSituations":"Cache corruption after a crash; double-applying void events during replay; adapter bugs emitting voided_qty larger than actual fills.","solutions":["Inspect the event sequence for the order and look for duplicate or oversized void_qty events.","Delete and rebuild the cached order state so events are re-fetched from the venue.","Clamp/validate voided_qty against accumulated filled qty before subtracting."],"exampleFix":"// before\nfilled -= event.voided_qty.as_decimal();\n// after\nlet new_filled = filled - event.voided_qty.as_decimal();\nanyhow::ensure!(new_filled >= Decimal::ZERO, \"voided qty exceeds fills\");\nfilled = new_filled;","handlingStrategy":"try-catch","validationCode":"if voided_qty > filled_qty { return Err(anyhow!(\"voided exceeds filled\")); }","typeGuard":null,"tryCatchPattern":"match venue_leg_filled_before_and_quantity(order, events, size_precision) {\n    Ok(q) => q,\n    Err(e) => { log::error!(\"fill reconstruction failed: {e:#}; rebuilding from venue\"); rebuild_order_from_venue(order_id)? }\n}","preventionTips":["Deduplicate void/cancel events during replay","Apply events in venue-issued sequence order","Rebuild cache from the venue after crash recovery"],"tags":["rust","reconciliation","invariant","order-state"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}