nautechsystems/nautilus_trader · error

provider GTD order {} requires a valid positive expiration

Error message

provider GTD order {} requires a valid positive expiration

What it means

When rebuilding an order report from a provider PolymarketOpenOrder, GTD (Good-Till-Date) orders must carry a parsable positive expiration timestamp. parse_provider_order_expiration returns Option<UnixNanos>; if the provider GTD order has no usable expiration, this anyhow error aborts validation in validate_order_row_values.

Source

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

        &format!("provider order {} matched quantity", order.id),
        true,
    )?;
    validate_price_evidence(
        order.price,
        price_precision,
        &format!("provider order {} price", order.id),
    )?;
    let ts_accepted = order
        .created_at
        .checked_mul(NANOSECONDS_IN_SECOND)
        .with_context(|| {
            format!(
                "provider order {} created_at seconds {} overflow Unix nanoseconds",
                order.id, order.created_at,
            )
        })?;
    let expire_time = parse_provider_order_expiration(order)?;
    anyhow::ensure!(
        TimeInForce::from(order.order_type) != TimeInForce::Gtd || expire_time.is_some(),
        "provider GTD order {} requires a valid positive expiration",
        order.id,
    );
    Ok(ValidatedOrderRow {
        venue_order_id: checked_venue_order_id(&order.id, "provider order")?,
        ts_accepted: UnixNanos::from(ts_accepted),
        expire_time,
    })
}

fn validate_trade_values(
    quantity: Decimal,
    price: Decimal,
    size_precision: u8,
    quantity_field: &str,
    price_field: &str,
) -> anyhow::Result<Price> {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Re-fetch the order from the Polymarket API to obtain its expiration and refresh the cached provider order.
  2. If the order is genuinely not time-limited, correct its order_type to Gtc so the GTD check does not apply.
  3. Fix the persistence layer to store/populate expiration UnixNanos for GTD orders instead of null/0.

Example fix

// before
let mut order = cached.clone(); // order_type: Gtd, expiration: None
let report = build_order_report_from_order(&provider_order, &order)?;
// after
order.set_time_in_force(TimeInForce::Gtd(UnixNanos::from(expire_unix_secs))); // populate before build
let report = build_order_report_from_order(&provider_order, &order)?;
Defensive patterns

Strategy: validation

Validate before calling

fn has_valid_gtd_expiration(order: &PolymarketOpenOrder) -> bool {
    TimeInForce::from(order.order_type) != TimeInForce::Gtd
        || order.expiration.map(|e| e.as_u64() > 0).unwrap_or(false)
}

Type guard

fn is_gtd_with_expiry(o: &PolymarketOpenOrder) -> Option<UnixNanos> {
    if TimeInForce::from(o.order_type) == TimeInForce::Gtd { o.expiration.filter(|e| e.as_u64() > 0) } else { None }
}

Try / catch

match build_order_report_from_order(&provider_order, &cached) {
    Err(e) if e.to_string().contains("requires a valid positive expiration") => {
        refresh_order_from_provider(&provider_order.id).await?; // re-fetch with expiration
    }
    other => other?,
}

Prevention

When it happens

Trigger: build_order_report_from_order processes a provider order whose order_type maps to TimeInForce::Gtd but the expiration field is missing, zero, negative, or unparseable, so expire_time is None.

Common situations: Provider API responses omitting the expiration for legacy GTC/GTD orders; epoch timestamp of 0 treated as no expiration; orders imported before the adapter began persisting expire_time; stale local order cache rows with null expiration columns.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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