nautechsystems/nautilus_trader · error · anyhow::Error

Invalid time range: start={s:?} end={e:?}

Error message

Invalid time range: start={s:?} end={e:?}

What it means

A time-range validation using anyhow::ensure!: when both start and end are provided for a historical data request, start must be strictly earlier than end, otherwise this error names both values. It is a client-side guard that prevents pointless doomed requests to OKX.

Source

Thrown at crates/adapters/okx/src/http/client.rs:3185

        start: Option<Timestamp>,
        end: Option<Timestamp>,
        limit: Option<u32>,
    ) -> anyhow::Result<Vec<TradeTick>> {
        const OKX_TRADES_MAX_LIMIT: u32 = 100;
        const MAX_PAGES: usize = 500;
        const MAX_CONSECUTIVE_EMPTY: usize = 3;

        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        enum Mode {
            Latest,
            Backward,
            Range,
        }

        let limit = if limit == Some(0) { None } else { limit };

        if let (Some(s), Some(e)) = (start, end) {
            anyhow::ensure!(s < e, "Invalid time range: start={s:?} end={e:?}");
        }

        let now = self.inner.clock.get_time_ns().to_datetime_utc();

        if let Some(s) = start
            && s > now
        {
            return Ok(Vec::new());
        }

        let end = if let Some(e) = end
            && e > now
        {
            Some(now)
        } else {
            end
        };

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Validate the range in your caller: assert start < end before invoking the request.
  2. Swap the values if your data source returns them in the opposite order.
  3. When start == end is meaningful (single point), omit one bound or widen the window by 1 unit.
  4. Review timezone handling so both bounds use the same tz before comparison.

Example fix

// before
let (start, end) = (end_ts, start_ts); // inverted by mistake
client.request_trades(instrument_id, Some(start), Some(end), None).await?;
// after
assert!(start_ts < end_ts, "start must precede end");
client.request_trades(instrument_id, Some(start_ts), Some(end_ts), None).await?;
Defensive patterns

Strategy: validation

Validate before calling

if let (Some(s), Some(e)) = (start, end) {
    assert!(s < e, "start must be before end: {s:?} vs {e:?}");
}

Try / catch

match client.request_trades(instrument_id, start, end, None).await {
    Err(e) if e.to_string().contains("Invalid time range") => { /* fix bounds and retry */ }
    other => other?,
}

Prevention

When it happens

Trigger: Calling a history/instruments request with start >= end (equal or inverted timestamps), e.g. passing the same datetime for both bounds or swapping them.

Common situations: Computing start/end from off-by-one window arithmetic, unit tests with identical timestamps, timezone conversions shifting end before start, or user-supplied query parameters passed through unvalidated.

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/25c0c93a1dd46fe2. Report an issue: GitHub.