nautechsystems/nautilus_trader · error
milliseconds {millis} is out of range for `u64` nanoseconds
Error message
milliseconds {millis} is out of range for `u64` nanoseconds What it means
millis_to_nanos multiplies by 1e6 and stores in u64, capped at ~1.8446744e19 nanoseconds (about 584 years, i.e. ~5.8e12 ms). This error means the input milliseconds exceed the u64 range after conversion.
Source
Thrown at crates/core/src/datetime.rs:320
///
/// Returns an error if `millis` is non-finite or cannot be represented as `u64` nanoseconds.
#[expect(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_precision_loss,
reason = "Intentional for unit conversion, may lose precision after clamping"
)]
pub fn millis_to_nanos(millis: f64) -> anyhow::Result<u64> {
anyhow::ensure!(
millis.is_finite(),
"milliseconds must be finite, was {millis}"
);
if millis <= 0.0 {
return Ok(0);
}
let nanos = millis * NANOSECONDS_IN_MILLISECOND as f64;
anyhow::ensure!(
nanos < U64_UPPER_BOUND_F64,
"milliseconds {millis} is out of range for `u64` nanoseconds"
);
Ok(nanos.trunc() as u64)
}
/// Converts milliseconds (ms) to nanoseconds (ns), panicking on invalid input.
///
/// # Panics
///
/// Panics if [`millis_to_nanos`] would return an error for `millis`.
#[must_use]
pub fn millis_to_nanos_unchecked(millis: f64) -> u64 {
millis_to_nanos(millis).expect("millis_to_nanos_unchecked: invalid or overflowing input")
}
/// Converts microseconds (μs) to nanoseconds (ns).
///View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the input unit; if it is already nanoseconds, do not convert again.
- Confirm whether the API expects a duration since epoch vs an offset; timestamps in ms since epoch (1.7e12) are fine, 1.7e15+ indicates a unit error.
- Range-check the value before conversion and reject implausible durations.
Example fix
// before let ns = millis_to_nanos(ns_timestamp as f64)?; // double conversion // after let ns = ns_timestamp; // already nanoseconds, no conversion needed
Defensive patterns
Strategy: validation
Validate before calling
const MAX_MILLIS_F64: f64 = 1.8446744e13; // u64::MAX nanoseconds in milliseconds
if !millis.is_finite() || millis < 0.0 || millis >= MAX_MILLIS_F64 {
return Err(format!("milliseconds out of convertible range: {millis}"));
} Type guard
fn is_convertible_millis(x: f64) -> bool { x.is_finite() && x > 0.0 && x < 1.8446744e13 } Try / catch
let ns = match millis_to_nanos(millis) {
Ok(ns) => ns,
Err(e) if e.to_string().contains("out of range") => { log::error!("unit confusion? millis={millis}"); bail!(e); }
Err(e) => return Err(e),
}; Prevention
- UNIX ms timestamps (~1.7e12) convert fine; values ~1.7e15+ indicate a unit error.
- Do not double-convert: check whether the value is already nanoseconds.
- Standardize the codebase on u64 nanoseconds to minimize conversions.
When it happens
Trigger: Calling millis_to_nanos with millis such that millis * 1e6 >= U64_UPPER_BOUND_F64 (millis >= ~1.8446744e13).
Common situations: Unit confusion — passing a nanosecond timestamp (1.7e18) as milliseconds; passing a raw UNIX millisecond timestamp where the API expects a duration; unvalidated numeric config values.
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
- seconds {secs} is out of range for `u64` nanoseconds
- seconds {secs} is out of range for `u64` milliseconds
- microseconds {micros} is out of range for `u64` nanoseconds
- DateTime timestamp out of range for UnixNanos: {nanos}
- Negative timestamp: {unix_timestamp_ns}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/fd8d1049d30137c5.
Report an issue: GitHub.