nautechsystems/nautilus_trader · error

Invalid timestamp

Error message

Invalid timestamp

What it means

In the Redis payload deserializer, `convert_timestamp_strings` parses timestamp-named string fields back into u64 nanoseconds via Jiff's `Timestamp` and then converts to u64 with `u64::try_from`. The expect() panics when the parsed timestamp is negative (pre-1970) or otherwise cannot be represented as an unsigned nanosecond count, i.e. the stored string was not a valid forward-direction Unix timestamp.

Source

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

        }
        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 {
                if is_timestamp_field(key)
                    && let Value::String(s) = v
                    && let Ok(dt) = s.parse::<Timestamp>()
                {
                    let nanos = u64::try_from(dt.as_nanosecond()).expect("Invalid timestamp");
                    *v = Value::Number(nanos.into());
                }
                convert_timestamp_strings(v);
            }
        }
        Value::Array(arr) => {
            for item in arr {
                convert_timestamp_strings(item);
            }
        }
        _ => {}
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the cached value and correct or delete the malformed timestamp string
  2. Ensure the writer used `serialize_payload`'s `{dt:.9}` UTC format; migrate old entries or bump the cache key/version
  3. Replace the expect with a logged skip/error so one bad field does not abort deserialization of the whole payload
  4. Validate strings with `s.parse::<Timestamp>()` plus a range check (>= 0 nanos) before the try_from

Example fix

// before
let nanos = u64::try_from(dt.as_nanosecond()).expect("Invalid timestamp");
// after
match u64::try_from(dt.as_nanosecond()) {
    Ok(nanos) => *v = Value::Number(nanos.into()),
    Err(_) => log::warn!("invalid timestamp string {s} for key {key}; leaving as string"),
}
Defensive patterns

Strategy: validation

Validate before calling

fn parse_ts_field(s: &str) -> Option<u64> {
    s.parse::<Timestamp>().ok()
        .and_then(|dt| u64::try_from(dt.as_nanosecond()).ok())
}

Type guard

fn is_valid_timestamp_string(s: &str) -> bool {
    s.parse::<Timestamp>().map(|dt| dt.as_nanosecond() >= 0).unwrap_or(false)
}

Try / catch

match u64::try_from(dt.as_nanosecond()) {
    Ok(nanos) => *v = Value::Number(nanos.into()),
    Err(_) => log::warn!("invalid timestamp string '{s}' for key '{key}'"),
}

Prevention

When it happens

Trigger: Calling `deserialize_payload` on a cached JSON blob whose timestamp field contains a malformed or pre-epoch string (e.g. "-123", "1970-01-01T00:00:00-05:00" with negative epoch, arbitrary text that happens to parse as Timestamp), or a string written by a different serializer format than `serialize_payload` produces.

Common situations: Redis cache populated by another application or older schema version; manual edits to cached values; timezone-offset strings whose instant is before the epoch; mixed-language clients writing ISO strings with different precision.

Related errors


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