nautechsystems/nautilus_trader · error
milliseconds must be finite, was {millis}
Error message
milliseconds must be finite, was {millis} What it means
millis_to_nanos received a non-finite f64 (NaN or infinity); such a value has no nanosecond representation after clamping and casting, so the conversion rejects it before producing a meaningless timestamp.
Source
Thrown at crates/core/src/datetime.rs:311
mins.checked_mul(SECONDS_IN_MINUTE)
}
/// Converts milliseconds (ms) to nanoseconds (ns).
///
/// Casting f64 to u64 by truncating the fractional part is intentional for unit conversion,
/// which may lose precision and drop negative values after clamping.
///
/// # Errors
///
/// 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.
///
/// # PanicsView on GitHub (pinned to 18893faf8b)
Solutions
- Check millis.is_finite() before calling and handle invalid values at the call site.
- Fix the upstream computation producing NaN/inf.
- Represent unknown durations as Option<u64>/Option<f64> instead of NaN/inf sentinels.
Example fix
// before
let ns = millis_to_nanos(latency_ms)?;
// after
anyhow::ensure!(latency_ms.is_finite(), "latency_ms not finite: {latency_ms}");
let ns = millis_to_nanos(latency_ms)?; Defensive patterns
Strategy: validation
Validate before calling
if !millis.is_finite() {
return Err(format!("milliseconds not finite: {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("must be finite") => { log::warn!("non-finite millis input"); 0 },
Err(e) => return Err(e),
}; Prevention
- Filter NaN/inf latency or interval measurements before conversion.
- Use Option<u64> for missing durations instead of NaN/inf floats.
- Add property tests covering non-finite inputs to conversion helpers.
When it happens
Trigger: Calling millis_to_nanos(f64::NAN) or millis_to_nanos(±f64::INFINITY).
Common situations: NaN from dividing interval values by zero; infinity from unchecked accumulation of latency measurements; placeholder values in market-data feeds marked missing as inf.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- seconds must be finite, was {secs}
- microseconds must be finite, was {micros}
- {e}
- {FAILED}: {e}
- {FAILED}: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c5dcee0cc0e49916.
Report an issue: GitHub.