nautechsystems/nautilus_trader · error
microseconds must be finite, was {micros}
Error message
microseconds must be finite, was {micros} What it means
Fired by micros_to_nanos when the f64 microsecond input cannot be converted to a u64 nanosecond count: it is non-finite (NaN or ±infinity) or its truncated, clamped value would overflow the u64 nanosecond range. It is a unit-conversion input validation guard protecting unchecked callers (micros_to_nanos_unchecked unwraps it).
Source
Thrown at crates/core/src/datetime.rs:352
millis_to_nanos(millis).expect("millis_to_nanos_unchecked: invalid or overflowing input")
}
/// Converts microseconds (μs) 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 `micros` 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 micros_to_nanos(micros: f64) -> anyhow::Result<u64> {
anyhow::ensure!(
micros.is_finite(),
"microseconds must be finite, was {micros}"
);
if micros <= 0.0 {
return Ok(0);
}
let nanos = micros * NANOSECONDS_IN_MICROSECOND as f64;
anyhow::ensure!(
nanos < U64_UPPER_BOUND_F64,
"microseconds {micros} is out of range for `u64` nanoseconds"
);
Ok(nanos.trunc() as u64)
}
/// Converts microseconds (μs) to nanoseconds (ns), panicking on invalid input.
///
/// # PanicsView on GitHub (pinned to 18893faf8b)
Solutions
- Guard with micros.is_finite() before calling and handle the invalid value at the source.
- Fix the upstream computation producing NaN/inf.
- Use Option<f64>/Option<u64> for unknown or unset microsecond values instead of NaN/inf.
Example fix
// before
let ns = micros_to_nanos(micros)?;
// after
if !micros.is_finite() { return Ok(0); }
let ns = micros_to_nanos(micros)?; Defensive patterns
Strategy: validation
Validate before calling
if !micros.is_finite() {
return Err(format!("microseconds not finite: {micros}"));
} Type guard
fn is_convertible_micros(x: f64) -> bool { x.is_finite() && x > 0.0 && x < 1.8446744e16 } Try / catch
let ns = match micros_to_nanos(micros) {
Ok(ns) => ns,
Err(e) if e.to_string().contains("must be finite") => { log::warn!("non-finite micros input"); 0 },
Err(e) => return Err(e),
}; Prevention
- Sanitize instrument-definition fields (e.g. ts_init, intervals) for NaN/inf before conversion.
- Avoid inf as a 'missing' sentinel; use Option.
- Validate parsed floats immediately after deserialization.
When it happens
Trigger: Calling micros_to_nanos(f64::NAN) or micros_to_nanos(±f64::INFINITY).
Common situations: NaN from malformed float parsing or 0/0 division upstream; infinity from overflowing arithmetic on timer deltas; missing-value sentinels (inf) in instrument definitions.
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}
- milliseconds must be finite, was {millis}
- {e}
- {FAILED}: {e}
- {FAILED}: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1796364efae231dc.
Report an issue: GitHub.