{"record":{"id":"ac520cb230fbe11e","repo":"nautechsystems/nautilus_trader","slug":"duplicate-fill","errorCode":null,"errorMessage":"Duplicate fill","messagePattern":"Duplicate fill","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/execution/src/engine/mod.rs","lineNumber":3486,"sourceCode":"\n        if self.config.debug {\n            log::debug!(\"Generated {} for {}\", position_id, fill.client_order_id());\n        }\n        position_id\n    }\n\n    fn determine_netting_position_id(&self, fill: &OrderFilled) -> PositionId {\n        PositionId::new(format!(\"{}-{}\", fill.instrument_id, fill.strategy_id))\n    }\n\n    fn validate_fill_for_order(&self, order: &OrderAny, fill: &OrderFilled) -> anyhow::Result<()> {\n        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(","sourceCodeStart":3468,"sourceCodeEnd":3504,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/execution/src/engine/mod.rs#L3468-L3504","documentation":"The engine validates fills before applying them: if the order reports the fill's trade_id as a duplicate (order.is_duplicate_fill), the fill is skipped and this error is raised instead of re-applying state. Duplicate fills would otherwise double-count fills/positions.","triggerScenarios":"Calling the engine's fill application path (e.g. update_order_filled / process_fill) with an OrderFilled event whose trade_id was already applied to the order — typically a replayed or duplicated venue event.","commonSituations":"Reconciliation re-delivering a fill that was already applied; venue/WebSocket message replay after reconnect; processing the same fill from both the execution report stream and reconciliation reports.","solutions":["This is a guard: treat it as 'already processed' and skip — deduplicate upstream by tracking processed trade_ids.","If your code propagates the error, catch it and continue when the fill is a benign duplicate.","Fix duplicate event delivery: check for double subscription or re-delivery after WebSocket reconnect.","If reconciliation is the source, let it skip already-applied fills instead of re-submitting them to the fill path."],"exampleFix":"// before\nengine.apply_fill(&order, &fill)?; // bails on replayed trade_id\n// after\nmatch engine.apply_fill(&order, &fill) {\n    Err(e) if e.to_string().contains(\"Duplicate fill\") => log::debug!(\"skipped duplicate {}\", fill.trade_id),\n    other => other?,\n}","handlingStrategy":"try-catch","validationCode":"// check before applying\nif order.is_duplicate_fill(&fill) { return Ok(()); }","typeGuard":null,"tryCatchPattern":"match engine.apply_fill(order, &fill) {\n    Err(e) if e.to_string().contains(\"Duplicate fill\") => log::debug!(\"fill {} already applied\", fill.trade_id),\n    other => other?,\n}","preventionTips":["Maintain a processed trade_id set on the caller side before forwarding fills to the engine.","Deduplicate reconciliation fill reports against already-applied live fills.","Guard against WebSocket replay/double delivery after reconnects."],"tags":["execution-engine","duplicate-fill","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"}