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
- Inspect the cached value and correct or delete the malformed timestamp string
- Ensure the writer used `serialize_payload`'s `{dt:.9}` UTC format; migrate old entries or bump the cache key/version
- Replace the expect with a logged skip/error so one bad field does not abort deserialization of the whole payload
- 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
- Write timestamps with the canonical `{dt:.9}` UTC format only
- Never hand-edit cached payload JSON; invalidate and rewrite instead
- Validate round-trip (serialize then deserialize) in tests
- Reject pre-epoch timestamps at write time
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
- UnixNanos is within Jiff's timestamp range
- UnixNanos overflow in from_seconds
- UnixNanos overflow in from_millis
- UnixNanos overflow in from_micros
- Close command should not be drained
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/85a956233effedc7.
Report an issue: GitHub.