{"record":{"id":"9e995b7a860fe1a6","repo":"nautechsystems/nautilus_trader","slug":"duplicate-position-fill","errorCode":null,"errorMessage":"Duplicate position fill","messagePattern":"Duplicate position fill","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/execution/src/engine/mod.rs","lineNumber":3498,"sourceCode":"        if order.is_duplicate_fill(fill) {\n            log::warn!(\n                \"Duplicate fill: {} trade_id={} already applied, skipping\",\n                order.client_order_id(),\n                fill.trade_id\n            );\n            anyhow::bail!(\"Duplicate fill\");\n        }\n\n        if let Some(position_id) = fill.position_id\n            && self.position_contains_trade_id(position_id, fill.trade_id)\n        {\n            log::warn!(\n                \"Duplicate fill: {} trade_id={} already applied to position {}, skipping\",\n                order.client_order_id(),\n                fill.trade_id,\n                position_id\n            );\n            anyhow::bail!(\"Duplicate position fill\");\n        }\n\n        self.check_overfill(order, fill)\n    }\n\n    fn validate_fill_for_order_projection(\n        &self,\n        order: &OrderAny,\n        fill: &OrderFilled,\n    ) -> anyhow::Result<()> {\n        if order.is_duplicate_fill(fill) {\n            anyhow::bail!(\"Duplicate fill\");\n        }\n\n        self.check_overfill(order, fill)\n    }\n\n    fn position_contains_trade_id(&self, position_id: PositionId, trade_id: TradeId) -> bool {","sourceCodeStart":3480,"sourceCodeEnd":3516,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/execution/src/engine/mod.rs#L3480-L3516","documentation":"Beyond the order-level duplicate check, the engine verifies that a fill's trade_id has not already been applied to the target position (position_contains_trade_id). If it has, the fill is skipped and this error is raised to prevent double-counting position quantities.","triggerScenarios":"Applying a fill whose trade_id is already recorded in the position's trade IDs even though the order-level duplicate check passed — e.g. the same trade_id applied to the same position from a second event path (reconciliation vs live stream).","commonSituations":"Reconciliation importing position reports that contain trades already applied via the live fill stream; hedge-position setups where one trade is reported against the same position twice; venue re-sending an execution report after reconnect.","solutions":["Treat as an idempotency guard: skip the fill if the position already contains the trade_id.","Deduplicate reconciliation data before applying: reconcile position reports against the engine's already-known trade IDs.","Check for double-delivery of fills from both the live stream and reconciliation, and prefer a single source of truth per position.","If the trade_id is genuinely different but colliding, verify the venue's trade ID semantics/normalization in the adapter."],"exampleFix":"// before\nengine.apply_fill(&order, &recon_fill)?; // trade already on position\n// after\nif !engine.position_contains_trade_id(position_id, recon_fill.trade_id) {\n    engine.apply_fill(&order, &recon_fill)?;\n}","handlingStrategy":"try-catch","validationCode":"// check before applying\nif engine.position_contains_trade_id(position_id, fill.trade_id) { return Ok(()); }","typeGuard":null,"tryCatchPattern":"match engine.apply_fill(order, &fill) {\n    Err(e) if e.to_string().contains(\"Duplicate position fill\") => log::debug!(\"trade {} already on position\", fill.trade_id),\n    other => other?,\n}","preventionTips":["Use a single source of truth per position when combining reconciliation and live fills.","Filter reconciliation trades already present in the position before applying.","Verify venue trade_id normalization in the adapter to avoid false collisions."],"tags":["execution-engine","duplicate-fill","position","idempotency","reconciliation","rust"],"backgroundTag":"duplicate-record-detected","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}