vectordotdev/vector · error

i64 -> f64 produced NaN

Error message

i64 -> f64 produced NaN

What it means

In GELF field coercion (`coerce_field_names_and_values`), timestamp values with sub-second milliseconds are converted via `ts_millis as f64 / 1000.0` and wrapped in `NotNan`. The `.expect` panics if the conversion produced NaN. The code comments note this division can never produce NaN for valid i64 inputs, so this is an internal invariant check against `ordered-float`'s NaN rejection.

Solutions

  1. Validate timestamps before ingestion (clamp to a sane range, e.g. within a few decades of now)
  2. Check upstream sources for malformed epoch values that could overflow the cast
  3. If reproducible, capture the event and report a bug with the timestamp value

Example fix

// before
NotNan::new(ts_millis as f64 / 1000.0).expect("i64 -> f64 produced NaN")
// after
let millis = ts_millis.clamp(-253_402_300_799_000, 253_402_300_799_000);
NotNan::new(millis as f64 / 1000.0).expect("i64 -> f64 produced NaN")
Defensive patterns

Strategy: validation

Validate before calling

// clamp timestamps to a representable range before GELF conversion
fn ts_in_range(t: &chrono::DateTime<chrono::Utc>) -> bool {
    let y = t.year();
    (1..=9999).contains(&y)
}

Prevention

When it happens

Trigger: Converting a GELF event whose timestamp field is a `Value::Timestamp` with non-zero milliseconds, if the i64-to-f64 cast unexpectedly yields NaN — essentially only with extreme i64 values outside safe f64 precision, which still cannot be NaN.

Common situations: Practically unreachable; could only surface with corrupted timestamps (e.g. far out-of-range values from a malformed input source) or a compiler/platform float anomaly.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/da3aa68eff103d1a. Report an issue: GitHub.

Appendix: source

Thrown at lib/codecs/src/encoding/format/gelf.rs:212

            match field.as_str() {
                VERSION | HOST | SHORT_MESSAGE | FULL_MESSAGE | FACILITY | FILE => {
                    if !value.is_bytes() {
                        err_invalid_type(field, "UTF-8 string", value.kind_str())?;
                    }
                }
                TIMESTAMP => {
                    if !(value.is_timestamp() || value.is_integer()) {
                        err_invalid_type(field, "timestamp or integer", value.kind_str())?;
                    }

                    // convert a `Value::Timestamp` to a GELF specified timestamp where milliseconds are represented by the fractional part of a float.
                    if let Value::Timestamp(ts) = value {
                        let ts_millis = ts.timestamp_millis();
                        if ts_millis % 1000 != 0 {
                            // i64 to f64 / 1000.0 will never be NaN
                            *value = Value::Float(
                                NotNan::new(ts_millis as f64 / 1000.0)
                                    .expect("i64 -> f64 produced NaN"),
                            );
                        } else {
                            // keep full range of representable time if no milliseconds are set
                            // but still convert to numeric according to GELF protocol
                            *value = Value::Integer(ts.timestamp())
                        }
                    }
                }
                LEVEL => {
                    if !value.is_integer() {
                        err_invalid_type(field, "integer", value.kind_str())?;
                    }
                }
                LINE => {
                    if !(value.is_float() || value.is_integer()) {
                        err_invalid_type(field, "number", value.kind_str())?;
                    }
                }

View on GitHub (pinned to bdb87aeaa4)