{"record":{"id":"0a5e32a36cd74597","repo":"nautechsystems/nautilus_trader","slug":"provider-outcome-outcome-does-not-match-instrume","errorCode":null,"errorMessage":"provider outcome {outcome} does not match instrument outcome {instrument_outcome}","messagePattern":"provider outcome (.+?) does not match instrument outcome (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/adapters/polymarket/src/execution/reconciliation.rs","lineNumber":259,"sourceCode":"    outcome: PolymarketOutcome,\n) -> anyhow::Result<()> {\n    let InstrumentAny::BinaryOption(binary) = instrument else {\n        anyhow::bail!(\"expected Polymarket BinaryOption instrument, found {instrument:?}\");\n    };\n    let instrument_condition = binary\n        .info\n        .as_ref()\n        .and_then(|info| info.get_str(\"condition_id\"))\n        .context(\"Polymarket instrument is missing condition_id metadata\")?;\n\n    anyhow::ensure!(\n        instrument_condition.eq_ignore_ascii_case(condition_id),\n        \"provider condition {condition_id} does not match instrument condition {instrument_condition}\",\n    );\n    let instrument_outcome = binary\n        .outcome\n        .context(\"Polymarket instrument is missing outcome metadata\")?;\n    anyhow::ensure!(\n        instrument_outcome == outcome.as_str(),\n        \"provider outcome {outcome} does not match instrument outcome {instrument_outcome}\",\n    );\n\n    Ok(())\n}\n\nfn validate_quantity_evidence(\n    value: Decimal,\n    precision: u8,\n    field: &str,\n    allow_zero: bool,\n) -> anyhow::Result<()> {\n    if allow_zero {\n        anyhow::ensure!(\n            value >= Decimal::ZERO,\n            \"{field} {value} must be non-negative\"\n        );","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/reconciliation.rs#L241-L277","documentation":"As part of binding a provider order/trade to the local instrument, the binary outcome (e.g. YES/NO) from the provider must exactly equal the instrument's outcome metadata. This error fires when the provider object's outcome differs from the instrument's configured outcome, so the fill would be attributed to the wrong side of the binary market.","triggerScenarios":"validate_instrument_binding (from build_order_report_from_order, classify_target_trade, build_fill_reports_from_trades) receives a provider object whose outcome string differs from binary.outcome, after the condition_id check passed (condition matched but outcome flipped).","commonSituations":"Trading the opposite token of the same market (YES vs NO) with an instrument configured for the other outcome; both outcomes share a condition_id so only this check catches it; outcome naming/casing differences from provider updates.","solutions":["Compare the token_id of the order/fill with the token_id configured for the instrument's outcome; ensure the right token is subscribed.","Fix the instrument configuration so binary.outcome matches the token actually being traded.","Normalize outcome strings if the provider changed casing or naming.","Refetch market metadata and rebuild the instrument if the market definition changed."],"exampleFix":"// before\nlet instrument = instrument_for_token(order.asset_id)?;\nvalidate_instrument_binding(&order, &instrument)?;\n// after: guard outcome before validation\nlet instrument = instrument_for_token(order.asset_id)?;\nif instrument.outcome.as_str() != order.outcome.as_str() {\n    anyhow::bail!(\"token {} maps to outcome {}, not {}\", order.asset_id, instrument.outcome, order.outcome);\n}\nvalidate_instrument_binding(&order, &instrument)?;","handlingStrategy":"validation","validationCode":"fn outcome_matches(instrument: &Instrument, outcome: &str) -> bool {\n    instrument.outcome.as_str() == outcome\n}","typeGuard":"fn instrument_for_outcome<'a>(instruments: &'a [Instrument], condition: &str, outcome: &str) -> Option<&'a Instrument> {\n    instruments.iter().find(|i| i.condition_id().eq_ignore_ascii_case(condition) && i.outcome.as_str() == outcome)\n}","tryCatchPattern":"match validate_instrument_binding(&fill, &instrument) {\n    Ok(()) => (),\n    Err(e) if e.to_string().contains(\"outcome\") => warn!(\"fill for opposite outcome token; skipping\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Key instrument lookup by token_id, not just condition_id (both outcomes share a condition)","Verify the subscribed token_id maps to the intended outcome before trading","Normalize outcome strings against the provider's exact naming"],"tags":["rust","polymarket","instrument-binding","outcome-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-14T00:17:10.932Z"}