nautechsystems/nautilus_trader · critical

provider outcome {outcome} does not match instrument outcome

Error message

provider outcome {outcome} does not match instrument outcome {instrument_outcome}

What it means

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.

Source

Thrown at crates/adapters/polymarket/src/execution/reconciliation.rs:259

    outcome: PolymarketOutcome,
) -> anyhow::Result<()> {
    let InstrumentAny::BinaryOption(binary) = instrument else {
        anyhow::bail!("expected Polymarket BinaryOption instrument, found {instrument:?}");
    };
    let instrument_condition = binary
        .info
        .as_ref()
        .and_then(|info| info.get_str("condition_id"))
        .context("Polymarket instrument is missing condition_id metadata")?;

    anyhow::ensure!(
        instrument_condition.eq_ignore_ascii_case(condition_id),
        "provider condition {condition_id} does not match instrument condition {instrument_condition}",
    );
    let instrument_outcome = binary
        .outcome
        .context("Polymarket instrument is missing outcome metadata")?;
    anyhow::ensure!(
        instrument_outcome == outcome.as_str(),
        "provider outcome {outcome} does not match instrument outcome {instrument_outcome}",
    );

    Ok(())
}

fn validate_quantity_evidence(
    value: Decimal,
    precision: u8,
    field: &str,
    allow_zero: bool,
) -> anyhow::Result<()> {
    if allow_zero {
        anyhow::ensure!(
            value >= Decimal::ZERO,
            "{field} {value} must be non-negative"
        );

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Compare the token_id of the order/fill with the token_id configured for the instrument's outcome; ensure the right token is subscribed.
  2. Fix the instrument configuration so binary.outcome matches the token actually being traded.
  3. Normalize outcome strings if the provider changed casing or naming.
  4. Refetch market metadata and rebuild the instrument if the market definition changed.

Example fix

// before
let instrument = instrument_for_token(order.asset_id)?;
validate_instrument_binding(&order, &instrument)?;
// after: guard outcome before validation
let instrument = instrument_for_token(order.asset_id)?;
if instrument.outcome.as_str() != order.outcome.as_str() {
    anyhow::bail!("token {} maps to outcome {}, not {}", order.asset_id, instrument.outcome, order.outcome);
}
validate_instrument_binding(&order, &instrument)?;
Defensive patterns

Strategy: validation

Validate before calling

fn outcome_matches(instrument: &Instrument, outcome: &str) -> bool {
    instrument.outcome.as_str() == outcome
}

Type guard

fn instrument_for_outcome<'a>(instruments: &'a [Instrument], condition: &str, outcome: &str) -> Option<&'a Instrument> {
    instruments.iter().find(|i| i.condition_id().eq_ignore_ascii_case(condition) && i.outcome.as_str() == outcome)
}

Try / catch

match validate_instrument_binding(&fill, &instrument) {
    Ok(()) => (),
    Err(e) if e.to_string().contains("outcome") => warn!("fill for opposite outcome token; skipping"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/0a5e32a36cd74597. Report an issue: GitHub.