nautechsystems/nautilus_trader · error

provider order price {} does not match cached order price {c

Error message

provider order price {} does not match cached order price {cached_price}

What it means

During Polymarket order reconciliation, the adapter validates that an open order returned by the provider matches the locally cached Nautilus order row before emitting an order status report. This error means the price on the provider's open order differs from the price of the cached Limit order, so the adapter cannot safely correlate the venue row with the client order. It is thrown because reconciling against a mismatched row would produce incorrect fill/order state.

Source

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

    provider_expire_time: Option<UnixNanos>,
) -> anyhow::Result<()> {
    anyhow::ensure!(
        cached_order.order_side() == provider_order.side.into(),
        "provider order side {} does not match cached order side {}",
        provider_order.side,
        cached_order.order_side(),
    );
    anyhow::ensure!(
        cached_order.time_in_force() == provider_order.order_type.into(),
        "provider order time in force {} does not match cached order time in force {}",
        provider_order.order_type,
        cached_order.time_in_force(),
    );
    validate_client_bound_order_quantity(provider_order, expected_quantity)?;
    let cached_price = cached_order
        .price()
        .context("cached Limit order is missing price")?;
    anyhow::ensure!(
        cached_price.as_decimal() == provider_order.price,
        "provider order price {} does not match cached order price {cached_price}",
        provider_order.price,
    );

    let provider_expire_seconds = provider_expire_time.map(|value| value.as_seconds());
    let cached_expire_seconds = cached_order
        .expire_time()
        .filter(|value| !value.is_zero())
        .map(|value| value.as_seconds());
    if cached_order.time_in_force() == TimeInForce::Gtd {
        anyhow::ensure!(
            cached_expire_seconds == provider_expire_seconds,
            "provider order expiration seconds {provider_expire_seconds:?} do not match cached order expiration seconds {cached_expire_seconds:?}",
        );
    }

    Ok(())

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Compare the cached order's price with the venue's reported price for that order id; update or clear the stale cache entry so it reflects the current venue price.
  2. Ensure price_precision on the instrument matches when the order was placed, and that the price passed to submit_order was not rounded differently (use instrument.make_price).
  3. Reconcile from scratch (drop the cached row and let the adapter import the venue order unbound), then rebind the client order id.
  4. If the order was legitimately amended, cancel and replace rather than editing cached state manually.

Example fix

// before: cache built from stale snapshot
let cached = cache.order(&client_order_id)?; // price 0.55
// after: refresh/validate cache against venue before reconciliation
let report = client.get_order(&venue_order_id).await?;
if cached.price().as_decimal() != report.price {
    // cancel stale row / re-import venue order instead of asserting
    log::warn!("cache drift for {venue_order_id}; re-importing venue state");
}
Defensive patterns

Strategy: validation

Validate before calling

if let Some(cached) = cache.order_for_venue(&venue_order_id) {
    let venue = client.get_order(&venue_order_id).await?;
    if cached.price().as_decimal() != venue.price {
        return Err(anyhow!("cache/venue price drift for {venue_order_id}: {} vs {}", cached.price(), venue.price));
    }
}

Type guard

fn prices_match(cached: &OrderAny, provider_price: Decimal) -> bool {
    cached.price().map(|p| p.as_decimal() == provider_price).unwrap_or(false)
}

Try / catch

match result {
    Err(e) if e.to_string().contains("does not match cached order price") => {
        log::warn!("stale cached order price; re-importing venue state");
        reconcile_unbound(&venue_order_id).await?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling order reconciliation (e.g. generate_order_status_reports / build_order_report_from_order) for a target order with a cached Limit order whose `price()` differs from `PolymarketOpenOrder.price` for the same venue order id. Happens when the cache holds a stale or wrong row for that venue_order_id, or when price fields from the venue come back in a different precision/representation so `cached_price.as_decimal() != provider_order.price`.

Common situations: Stale cache after the order was amended/repriced but the cached price was not updated; restoring state from an old cache file while venue orders moved; restart with a different price precision/rounding config than when the order was placed; fetching reports for a venue order id that was reused or remapped to a different client order.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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