{"record":{"id":"a3f6af6c8549df2a","repo":"nautechsystems/nautilus_trader","slug":"provider-trade-repeats-with-contradictory-evide","errorCode":null,"errorMessage":"provider trade {} repeats with contradictory evidence","messagePattern":"provider trade (.+?) repeats with contradictory evidence","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/reconciliation.rs","lineNumber":1033,"sourceCode":"    /// Whether valid unsettled evidence for the requested venue order was found.\n    pub has_pending_target: bool,\n    /// Fill entries dropped because their instrument is not loaded.\n    pub unmapped_instruments: usize,\n    /// In-scope historical fills dropped because their instrument is not loaded.\n    pub in_scope_historical: usize,\n    /// Confirmed maker trades dropped because no maker order in the match is\n    /// owned by the account.\n    pub unowned_maker_trades: usize,\n    /// Confirmed trades dropped from a bounded report because their event time is invalid.\n    pub untimestamped_trades: usize,\n}\n\nfn admit_selected_trade<'a>(\n    selected_trades: &mut AHashMap<&'a str, &'a PolymarketTradeReport>,\n    trade: &'a PolymarketTradeReport,\n) -> anyhow::Result<bool> {\n    if let Some(previous) = selected_trades.get(trade.id.as_str()) {\n        anyhow::ensure!(\n            *previous == trade,\n            \"provider trade {} repeats with contradictory evidence\",\n            trade.id,\n        );\n        return Ok(false);\n    }\n\n    selected_trades.insert(trade.id.as_str(), trade);\n    Ok(true)\n}\n\n/// Converts trade reports into fill reports: single implementation of maker/taker\n/// parsing used by both `generate_fill_reports()` and `generate_mass_status()`.\npub(crate) fn build_fill_reports_from_trades(\n    trades: &[PolymarketTradeReport],\n    ctx: &FillContext<'_>,\n    instruments: &AtomicMap<Ustr, InstrumentAny>,\n    scope: FillReportScope,","sourceCodeStart":1015,"sourceCodeEnd":1051,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/reconciliation.rs#L1015-L1051","documentation":"During trade reconciliation, `admit_selected_trade` deduplicates provider trade reports by trade id. If a trade id is seen a second time, the report must be byte-for-byte identical to the first; any differing field means the provider returned contradictory evidence for the same trade, so reconciliation aborts with `anyhow::ensure!` instead of silently picking one version.","triggerScenarios":"Calling Polymarket fill/trade reconciliation (e.g. generate_fill_reports / generate_order_status_reports flow that admits selected trades) when the provider returns two report payloads with the same trade id but differing fields (different price, size, side, timestamp, or status), typically across multiple pages/queries whose data was updated in between fetches.","commonSituations":"Provider API pagination overlapping while the venue retroactively amended a trade; a partially settled trade whose fields changed between two reconciliation fetches; caching stale report snapshots and re-admitting them after new data arrived; replaying the same trade with corrected data after a venue settlement adjustment.","solutions":["Re-fetch the trade reports in a single pass and confirm the provider data is stable; if the venue genuinely amended the trade, rebuild/refresh the local execution state before reconciling.","Check for stale caching or overlapping pagination in the code that collects PolymarketTradeReport items; deduplicate only identical payloads before calling reconciliation.","Compare the two conflicting payloads (log the diff of the PolymarketTradeReport fields) to identify which field disagrees, then verify against the Polymarket Data API which version is authoritative.","If the adapter version predates a venue data-amendment behavior, upgrade the nautilus_polymarket adapter to a version that reconciles amended trades instead of failing."],"exampleFix":"// before: reconciliation hard-fails on an amended provider trade\nanyhow::ensure!(\n    *previous == trade,\n    \"provider trade {} repeats with contradictory evidence\",\n    trade.id,\n);\n// after: detect and refresh stale snapshots upstream so duplicates are identical\nlet mut deduped: AHashMap<&str, &PolymarketTradeReport> = AHashMap::new();\nfor trade in fetched_trades {\n    deduped.entry(trade.id.as_str())\n        .and_modify(|prev| assert_eq!(*prev, trade, \"re-fetch trade {} for stable snapshot\", trade.id))\n        .or_insert(trade);\n}","handlingStrategy":"validation","validationCode":"let mut seen: AHashMap<&str, &PolymarketTradeReport> = AHashMap::new();\nfor trade in trades {\n    if let Some(prev) = seen.get(trade.id.as_str()) {\n        if *prev != trade {\n            return Err(anyhow::anyhow!(\n                \"trade {} payload changed between fetches; refresh snapshot before reconciling\",\n                trade.id,\n            ));\n        }\n    } else {\n        seen.insert(trade.id.as_str(), trade);\n    }\n}","typeGuard":"fn is_stable_repeat<'a>(prev: &&'a PolymarketTradeReport, next: &'a PolymarketTradeReport) -> bool {\n    *prev == next\n}","tryCatchPattern":"match reconciliation_result {\n    Err(e) if e.to_string().contains(\"repeats with contradictory evidence\") => {\n        log::warn!(\"provider data changed mid-reconciliation; re-fetching trades\");\n        retry_with_fresh_snapshot();\n    }\n    other => other?,\n}","preventionTips":["Fetch trade reports in a single consistent query window before reconciling","Deduplicate identical payloads across pagination pages before admitting trades","Do not mix cached snapshots with fresh fetches in one reconciliation pass","Keep the adapter up to date for venue trade-amendment behavior"],"tags":["reconciliation","data-integrity","polymarket","duplicate-data"],"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-14T05:17:10.506Z"}