nautechsystems/nautilus_trader · error

UnixNanos is within Jiff's timestamp range

Error message

UnixNanos is within Jiff's timestamp range

What it means

In the Redis payload serializer, `convert_timestamps` rewrites numeric Unix-nanosecond timestamp fields into Jiff `Timestamp` strings formatted with nanosecond precision. The expect() asserts that any u64 field recognized as a timestamp fits within Jiff's supported timestamp range (roughly years -9999..9999). It panics when the numeric value is too large (or absurdly small) to be a real nanosecond timestamp.

Source

Thrown at crates/infrastructure/src/redis/queries.rs:1041

        .map_err(|e| anyhow::anyhow!("Failed to parse instrument ID from key '{key}': {e}"))
}

fn is_timestamp_field(key: &str) -> bool {
    let expire_match = key == "expire_time_ns";
    let ts_match = key.starts_with("ts_");
    expire_match || ts_match
}

fn convert_timestamps(value: &mut Value) {
    match value {
        Value::Object(map) => {
            for (key, v) in map {
                if is_timestamp_field(key)
                    && let Value::Number(n) = v
                    && let Some(n) = n.as_u64()
                {
                    let dt = Timestamp::from_nanosecond(i128::from(n))
                        .expect("UnixNanos is within Jiff's timestamp range");
                    *v = Value::String(format!("{dt:.9}"));
                }
                convert_timestamps(v);
            }
        }
        Value::Array(arr) => {
            for item in arr {
                convert_timestamps(item);
            }
        }
        _ => {}
    }
}

fn convert_timestamp_strings(value: &mut Value) {
    match value {
        Value::Object(map) => {
            for (key, v) in map {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the stored value is actually nanoseconds since the Unix epoch; convert milliseconds/microseconds to nanoseconds before caching
  2. Rename the offending field so `is_timestamp_field` no longer matches it, or adjust the key matcher
  3. Clamp/skip conversion for values outside Jiff's range instead of expect() (return the original value or an error)
  4. Read the raw value at the source (redis GET / payload dump) and fix the producer writing the bad number

Example fix

// before
let dt = Timestamp::from_nanosecond(i128::from(n))
    .expect("UnixNanos is within Jiff's timestamp range");
// after
if let Ok(dt) = Timestamp::from_nanosecond(i128::from(n)) {
    *v = Value::String(format!("{dt:.9}"));
} else {
    log::warn!("skipping non-representable timestamp value {n} for key {key}");
}
Defensive patterns

Strategy: validation

Validate before calling

const MAX_NANOS: i128 = 253_402_300_799_999_999_999; // 9999-12-31
fn is_valid_unix_nanos(n: u64) -> bool {
    (i128::from(n)) <= MAX_NANOS && n / 1_000_000_000 > 0
}

Type guard

fn as_unix_nanos(v: &serde_json::Value) -> Option<u64> {
    match v { Value::Number(n) => n.as_u64().filter(|n| Timestamp::from_nanosecond(i128::from(*n)).is_ok()), _ => None }
}

Try / catch

match Timestamp::from_nanosecond(i128::from(n)) {
    Ok(dt) => *v = Value::String(format!("{dt:.9}")),
    Err(e) => return Err(format!("timestamp field '{key}' out of range: {e}")),
}

Prevention

When it happens

Trigger: Calling `serialize_payload` on a payload where a field matched by `is_timestamp_field` (e.g. keys containing 'timestamp', 'ts') holds a u64 that is not a valid UnixNanos — such as an ID mistakenly named like a timestamp, nanoseconds stored as milliseconds*1e6 wrongly, or a corrupted/hand-edited value exceeding i128 nanoseconds representable by Jiff (≈ year 9999).

Common situations: Cache payloads written by an older nautilus version with different field naming; JSON produced by external systems where 'timestamp'-like keys hold sequence numbers or hashes; unit tests feeding synthetic large u64 values into timestamp-named fields.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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