{"record":{"id":"f4d0c704326270b9","repo":"nautechsystems/nautilus_trader","slug":"replacement-venue-leg-side-does-not-match-log","errorCode":null,"errorMessage":"replacement venue-leg side {:?} does not match logical order side {}","messagePattern":"replacement venue-leg side (.+?) does not match logical order side (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/reports.rs","lineNumber":727,"sourceCode":"            };\n\n            let context = self\n                .order_contexts\n                .get(&promotion.old_venue_order_id)\n                .context(\"pending modification has no old-leg context\")?;\n            anyhow::ensure!(\n                report.quantity == promotion.leg_quantity,\n                \"replacement venue-leg quantity {} does not match signed quantity {}\",\n                report.quantity,\n                promotion.leg_quantity,\n            );\n            anyhow::ensure!(\n                report.price == Some(promotion.price),\n                \"replacement venue-leg price {:?} does not match signed price {}\",\n                report.price,\n                promotion.price,\n            );\n            anyhow::ensure!(\n                report.order_side == Some(context.identity.order_side),\n                \"replacement venue-leg side {:?} does not match logical order side {}\",\n                report.order_side,\n                context.identity.order_side,\n            );\n            let cached_order = self\n                .core\n                .cache()\n                .order_owned(&promotion.client_order_id)\n                .context(\"pending modification has no cached logical order\")?;\n\n            if report.order_status == OrderStatus::Rejected {\n                let finish = self\n                    .ws_dispatch_state\n                    .lock()\n                    .finish_modify_without_replacement(\n                        promotion.client_order_id,\n                        promotion.old_venue_order_id,","sourceCodeStart":709,"sourceCodeEnd":745,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/reports.rs#L709-L745","documentation":"During replacement-leg promotion, the venue report's order side must match the logical order side recorded in the old leg's context identity. Polymarket legs can be expressed via token buys, so the adapter maps logical BUY/SELL to venue-leg sides; this ensure! fires when the venue's reported side disagrees with that mapping.","triggerScenarios":"generate_order_status_reports promotes a pending modification and report.order_side is None or differs from context.identity.order_side — e.g. side inversion in the replace/leg construction.","commonSituations":"Incorrect BUY/SELL mapping when constructing the replacement leg (e.g. SELL implemented as BUY of the complement token); venue returning side for the wrong leg; context built with the wrong logical side at registration.","solutions":["Fix the logical-to-venue-leg side mapping in the replacement construction","Verify the context identity side matches the original submitted order","Inspect the venue response to confirm which leg the report refers to","Re-register the context with the correct side and retry"],"exampleFix":"// before\nlet leg_side = if order.side() == OrderSide::Buy { Buy } else { Buy }; // wrong: always Buy\n// after\nlet leg_side = venue_leg_side_for(order.side(), token_id); // correct logical mapping","handlingStrategy":"validation","validationCode":"let expected_side = venue_leg_side_for(order.side(), leg_token_id);\nanyhow::ensure!(context.identity.order_side == order.side(), \"context side must match logical order side\");","typeGuard":"fn side_matches(report: &OrderStatusReport, ctx: &OrderContext) -> bool {\n    report.order_side == Some(ctx.identity.order_side)\n}","tryCatchPattern":"match report.order_side {\n    Some(s) if s != context.identity.order_side => error!(\"side inversion in replace leg — abort promotion\"),\n    None => warn!(\"venue omitted side; falling back to context side\"),\n    _ => {},\n}","preventionTips":["Centralize the logical-side to venue-leg-side mapping in one tested function","Add unit tests covering BUY and SELL replacements on both outcome tokens","Never hardcode side conversions inline in report-generation code"],"tags":["rust","order-side","order-modification","venue-mismatch"],"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"}