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
- Refresh the cached order's time_in_force from the provider's authoritative order_type and retry reconciliation.
- Ensure the TIF recorded in the SubmitOrder command is what is stored in the cache (no defaulting to Gtc for GTD orders).
- Check the provider order_type -> TimeInForce conversion in the adapter for a regression after a Polymarket API/SDK update.
- 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
- Never default cached time_in_force to Gtc — always derive it from the submitted order_type
- Apply provider amend/update events to the cache before reconciliation
- Add regression tests for the order_type -> TimeInForce mapping when the adapter or provider API changes
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
- provider order quantity {} does not match cached order quant
- provider order side {} does not match cached order side {}
- unmapped_in_scope_message("open order", instrument_id, Some(
- unmapped_in_scope_message("position", instrument_id, None, c
- Unsupported `TimeInForce` for Polymarket: {value:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/7fda81d433c7d8c9.
Report an issue: GitHub.