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
- Verify the stored value is actually nanoseconds since the Unix epoch; convert milliseconds/microseconds to nanoseconds before caching
- Rename the offending field so `is_timestamp_field` no longer matches it, or adjust the key matcher
- Clamp/skip conversion for values outside Jiff's range instead of expect() (return the original value or an error)
- 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
- Only name fields as timestamps when they truly hold UnixNanos
- Store epoch values in nanoseconds consistently (ms/us conversions at the boundary)
- Version your cache keys so payload schema changes invalidate old entries
- Range-check timestamp values at ingestion
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
- Invalid timestamp
- 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/bd35d570c05950eb.
Report an issue: GitHub.