nautechsystems/nautilus_trader · error

provider order time in force {} does not match cached order

Error message

provider order time in force {} does not match cached order time in force {}

What it means

The last cross-check in validate_client_bound_order_row compares the cached order's time_in_force with the provider order_type (converted via TimeInForce::From). If the venue-side order type (e.g. GTC, GTD, FOK, FAK) differs from what the client cached, this anyhow error fires, since reconciling against a differently-timed order would corrupt order-state tracking.

Source

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

        provider_order.original_size,
        expected_quantity,
    );
    Ok(())
}

fn validate_client_bound_order_row(
    provider_order: &PolymarketOpenOrder,
    cached_order: &OrderAny,
    expected_quantity: Quantity,
    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()

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Refresh the cached order's time_in_force from the provider's authoritative order_type and retry reconciliation.
  2. Ensure the TIF recorded in the SubmitOrder command is what is stored in the cache (no defaulting to Gtc for GTD orders).
  3. Check the provider order_type -> TimeInForce conversion in the adapter for a regression after a Polymarket API/SDK update.
  4. If the order was legitimately amended on-venue, process the provider modify/update event so the cache reflects the new TIF before building the report.

Example fix

// before
let mut cached = build_order(req)?; // req.tif = Gtd
cached.set_time_in_force(TimeInForce::Gtc); // accidental default
let report = build_order_report_from_order(&provider_order, &cached)?;
// after
cached.set_time_in_force(TimeInForce::from(req.order_type)); // Gtd matches provider
let report = build_order_report_from_order(&provider_order, &cached)?;
Defensive patterns

Strategy: validation

Validate before calling

fn tif_matches(provider: &PolymarketOpenOrder, cached: &OrderAny) -> bool {
    cached.time_in_force() == provider.order_type.into()
}
// verify at submission time:
anyhow::ensure!(TimeInForce::from(submit_cmd.order_type) == submit_cmd.time_in_force, "TIF mismatch");

Type guard

fn tif_consistent(p: &PolymarketOpenOrder, c: &OrderAny) -> bool {
    c.time_in_force() == p.order_type.into()
}

Try / catch

match build_order_report_from_order(&provider_order, &cached) {
    Err(e) if e.to_string().contains("does not match cached order time in force") => {
        refresh_cached_tif_from_provider(&mut cached, provider_order.order_type); // resync then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: build_order_report_from_order -> validate_client_bound_order_row encounters a provider order_type that maps to a different TimeInForce than cached_order.time_in_force() — e.g. the order was amended on-venue to a different type, or the local cache recorded Gtc for an order submitted as Gtd/Fok.

Common situations: Provider amended the order's expiration/type after submission while the cache kept the original TIF; adapter version upgrade changing the order_type -> TimeInForce mapping (e.g. FOK vs FAK semantics); strategy submitted a GTD order but the cache defaulted to GTC; provider reclassified an expired GTD order as GTC.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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