{"record":{"id":"45f4d299d85475df","repo":"nautechsystems/nautilus_trader","slug":"instrument-metadata-does-not-match-fill-group","errorCode":null,"errorMessage":"instrument metadata does not match fill group","messagePattern":"instrument metadata does not match fill group","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/live/src/execution/manager.rs","lineNumber":1301,"sourceCode":"            anyhow::ensure!(\n                fill.venue_order_id == first.venue_order_id,\n                \"venue order ID differs across fill group\"\n            );\n            anyhow::ensure!(\n                fill.client_order_id == first.client_order_id,\n                \"client order ID differs across fill group\"\n            );\n            anyhow::ensure!(\n                fill.order_side == first.order_side,\n                \"order side differs across fill group\"\n            );\n            anyhow::ensure!(\n                fill.venue_position_id == first.venue_position_id,\n                \"venue position ID differs across fill group\"\n            );\n        }\n\n        anyhow::ensure!(\n            first.instrument_id == instrument.id(),\n            \"instrument metadata does not match fill group\"\n        );\n\n        let (quantity, notional) = fills.iter().try_fold(\n            (Decimal::ZERO, Decimal::ZERO),\n            |(quantity, notional), fill| {\n                let fill_quantity = fill.last_qty.as_decimal();\n                let quantity = quantity.checked_add(fill_quantity).ok_or_else(|| {\n                    anyhow::anyhow!(\"fill quantity overflow while aggregating fill group\")\n                })?;\n\n                let fill_notional = fill_quantity\n                    .checked_mul(fill.last_px.as_decimal())\n                    .ok_or_else(|| {\n                        anyhow::anyhow!(\"fill notional overflow while aggregating fill group\")\n                    })?;\n","sourceCodeStart":1283,"sourceCodeEnd":1319,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/live/src/execution/manager.rs#L1283-L1319","documentation":"create_orphan_fill_order_report receives the InstrumentAny whose metadata (precision, size precision, etc.) will be used to build the synthetic OrderStatusReport. This ensure! verifies that instrument.id() matches the instrument_id carried by the fill group; a mismatch means the wrong instrument definition was looked up for these fills, so the report cannot be constructed safely.","triggerScenarios":"During reconciliation, the instrument passed to create_orphan_fill_order_report was resolved from the cache or reconciliation_instrument_ids by a different instrument_id than the one on the FillReport group — e.g. a stale/aliased instrument definition or a cache keyed by the wrong ID.","commonSituations":"Instrument definitions reloaded with a changed symbol/venue after a venue rename; loading instruments for the wrong venue into the cache; symbol aliasing differences (e.g. perpetual suffixes) between the adapter and the cached instrument; replaying historical data with old instrument IDs.","solutions":["Verify the instrument lookup used for reconciliation resolves exactly the fill's instrument_id (compare instrument.id() with fill.instrument_id before calling).","Reload the instrument definitions from the venue so cached instrument IDs match the IDs in current fill reports.","Check for symbol aliasing or venue-name mismatches between the adapter's instrument IDs and those in your cache/catalog.","If loading instruments from a saved catalog, regenerate them for the current venue and version instead of reusing stale files."],"exampleFix":"// before: fetched by assumed symbol\nlet instrument = cache.instrument(&assumed_id)?;\n// after: resolve by the fill's own instrument ID\nlet instrument = cache.instrument(&first.instrument_id)\n    .ok_or_else(|| anyhow::anyhow!(\"instrument {} not in cache\", first.instrument_id))?;","handlingStrategy":"validation","validationCode":"assert_eq!(instrument.id(), first.instrument_id, \"instrument {} does not match fill group instrument {}\", instrument.id(), first.instrument_id);","typeGuard":"fn instrument_matches(instrument: &InstrumentAny, first: &FillReport) -> bool {\n    instrument.id() == first.instrument_id\n}","tryCatchPattern":null,"preventionTips":["Resolve instruments by the FillReport's instrument_id, never by an assumed or aliased symbol.","Reload instrument definitions from the venue whenever symbols, venue names, or adapter versions change.","Assert instrument.id() == fill.instrument_id at the boundary where instruments are loaded into the cache."],"tags":["reconciliation","rust","instrument","id-mismatch"],"backgroundTag":"invalid-argument-value","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"}