nautechsystems/nautilus_trader · error

microseconds {micros} is out of range for `u64` nanoseconds

Error message

microseconds {micros} is out of range for `u64` nanoseconds

What it means

micros_to_nanos multiplies by 1e3 and stores in u64, capped at ~1.8446744e19 nanoseconds (about 1.8446744e16 microseconds). This error means the input microseconds exceed the u64 range after conversion.

Source

Thrown at crates/core/src/datetime.rs:361

///
/// 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.
///
/// # Panics
///
/// Panics if [`micros_to_nanos`] would return an error for `micros`.
#[must_use]
pub fn micros_to_nanos_unchecked(micros: f64) -> u64 {
    micros_to_nanos(micros).expect("micros_to_nanos_unchecked: invalid or overflowing input")
}

/// Converts nanoseconds (ns) to seconds.
///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the input unit; if the value is already nanoseconds, skip the conversion.
  2. Range-check the microsecond value before conversion and reject/clamp implausible values.
  3. Standardize on one time unit (nanoseconds u64) across the codebase to avoid repeated conversions.

Example fix

// before
let ns = micros_to_nanos(ns_value as f64)?; // overflow
// after
let ns = ns_value; // already nanoseconds
Defensive patterns

Strategy: validation

Validate before calling

const MAX_MICROS_F64: f64 = 1.8446744e16; // u64::MAX nanoseconds in microseconds
if !micros.is_finite() || micros < 0.0 || micros >= MAX_MICROS_F64 {
    return Err(format!("microseconds out of convertible range: {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("out of range") => { log::error!("unit confusion? micros={micros}"); bail!(e); }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: Calling micros_to_nanos with micros such that micros * 1e3 >= U64_UPPER_BOUND_F64 (micros >= ~1.8446744e16).

Common situations: Unit confusion — passing a nanosecond timestamp (1.7e18) as microseconds; passing millisecond values where microseconds are expected repeatedly compounded by conversions; unvalidated numeric input from config or feeds.

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/a189e273814d5973. Report an issue: GitHub.