{"record":{"id":"9b5dbe1df536d309","repo":"nautechsystems/nautilus_trader","slug":"trade-trader-side-contradicts-target-order","errorCode":null,"errorMessage":"trade {} trader_side {:?} contradicts target order {venue_order_id} participant role","messagePattern":"trade (.+?) trader_side (.+?) contradicts target order (.+?) participant role","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/reconciliation.rs","lineNumber":171,"sourceCode":"    venue_order_id: VenueOrderId,\n) -> anyhow::Result<bool> {\n    let target_is_taker = trade.taker_order_id == venue_order_id.as_str();\n    let target_maker_occurrences = trade\n        .maker_orders\n        .iter()\n        .filter(|order| order.order_id == venue_order_id.as_str())\n        .count();\n    let target_is_maker = target_maker_occurrences > 0;\n    if !target_is_taker && !target_is_maker {\n        return Ok(false);\n    }\n    anyhow::ensure!(\n        usize::from(target_is_taker) + target_maker_occurrences == 1,\n        \"target order {venue_order_id} appears more than once in trade {}\",\n        trade.id,\n    );\n    let declared_maker = trade.trader_side == PolymarketLiquiditySide::Maker;\n    anyhow::ensure!(\n        declared_maker == target_is_maker,\n        \"trade {} trader_side {:?} contradicts target order {venue_order_id} participant role\",\n        trade.id,\n        trade.trader_side,\n    );\n    Ok(true)\n}\n\nfn validate_maker_order_side(\n    trade: &PolymarketTradeReport,\n    maker_order: &PolymarketMakerOrder,\n) -> anyhow::Result<OrderSide> {\n    let derived_side = determine_order_side(\n        trade.trader_side,\n        trade.side,\n        trade.asset_id.as_str(),\n        maker_order.asset_id.as_str(),\n    );","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/reconciliation.rs#L153-L189","documentation":"After determining the target order's role in the trade (maker or taker), the code cross-checks the trade's declared trader_side field. This error fires when the declared side (Maker/Taker) contradicts the order's actual participant role in the trade — the provider data is internally inconsistent.","triggerScenarios":"classify_target_trade -> validate_target_trade_role sees target_is_maker true while trade.trader_side is not Maker (or vice versa), e.g. trade.trader_side == Taker but the venue order id only appears in the maker list.","commonSituations":"Provider data-api returning inconsistent trader_side after a trade format change; a trade where the authenticated trader fields are mismatched to the order list; cached/stale trade objects merged incorrectly.","solutions":["Log the trade payload and compare trade.trader_side against the order's position in maker_orders vs taker fields.","Re-fetch the trade from the provider API to rule out a stale or mid-update record.","Check for recent Polymarket API schema changes affecting trader_side semantics and update parsing.","Drop the inconsistent trade from reconciliation and surface it for manual review."],"exampleFix":"// before\nanyhow::ensure!(declared_maker == target_is_maker, ...);\n// after: detect and skip contradictory trades upstream\nif (trade.trader_side == PolymarketLiquiditySide::Maker) != target_is_maker {\n    warn!(\"trade {} has contradictory trader_side; skipping\", trade.id);\n    return Ok(false);\n}","handlingStrategy":"validation","validationCode":"fn trader_side_consistent(trade: &Trade, vid: &str) -> bool {\n    let is_maker = trade.maker_orders.iter().any(|o| o.order_id == vid);\n    (trade.trader_side == PolymarketLiquiditySide::Maker) == is_maker\n}","typeGuard":"fn declared_side_matches_role(trade: &Trade, vid: &str) -> bool {\n    let role_is_maker = trade.maker_orders.iter().any(|o| o.order_id == vid);\n    match trade.trader_side {\n        PolymarketLiquiditySide::Maker => role_is_maker,\n        PolymarketLiquiditySide::Taker => !role_is_maker,\n    }\n}","tryCatchPattern":"match classify_target_trade(&trade, &venue_order_id) {\n    Ok(is_target) => { /* proceed */ }\n    Err(e) if e.to_string().contains(\"contradicts\") => warn!(\"inconsistent trade skipped: {e}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Validate trader_side against the role list immediately after parsing provider trades","Re-fetch trades that look inconsistent before discarding them","Track Polymarket API changelog for trader_side semantics changes"],"tags":["rust","reconciliation","polymarket","data-integrity"],"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"}