databendlabs/databend · error

Sum resulted in NaN

Error message

Sum resulted in NaN

What it means

The Sum impl for NotNan<T> folds the iterator's underlying floats with std's Sum and rewraps via NotNan::new. If the accumulated sum is NaN (any NaN element, or inf + -inf intermediate), NotNan::new panics with this message. The wrapper intentionally refuses to let NaN flow into ordered float collections.

Solutions

  1. Filter non-finite values before summing: `iter.filter(|v| v.is_finite()).sum()`.
  2. Collect into f64, sum, and check: `NotNan::new(vals.iter().sum::<f64>()).ok()` with explicit NaN handling.
  3. Fix upstream computations that emit inf (guard divisions, clamp overflow) before the sum.

Example fix

// before
let total: NotNan<f64> = values.iter().copied().sum(); // panics on NaN result
// after
let total: NotNan<f64> = values.iter().copied().filter(|v| v.is_finite()).sum();
Defensive patterns

Strategy: validation

Validate before calling

fn safe_sum(vals: &[NotNan<f64>]) -> Option<NotNan<f64>> {
    if vals.iter().all(|v| v.is_finite()) {
        let raw: f64 = vals.iter().map(|v| v.0).sum();
        NotNan::new(raw).ok()
    } else { None }
}

Type guard

fn all_finite(vals: &[NotNan<f64>]) -> bool { vals.iter().all(|v| v.is_finite()) }

Try / catch

let total = std::panic::catch_unwind(|| vals.iter().copied().sum::<NotNan<f64>>()).ok();

Prevention

When it happens

Trigger: `iter.sum::<NotNan<f64>>()` where the iterator contains a NaN NotNan (constructible only via unsafe or prior bugs) or where the running sum becomes NaN through inf + -inf cancellation of infinite elements.

Common situations: Aggregating columns of computed values where some rows contain infinities from division by zero, so +inf and -inf sums cancel to NaN; also summing very large magnitudes that overflow to inf on both signs.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/30dfd60d203d525a. Report an issue: GitHub.

Appendix: source

Thrown at src/common/base/src/base/ordered_float.rs:1329

/// Adds a float directly.
///
/// Panics if the provided value is NaN or the computation results in NaN
impl<T: FloatCore> Add<T> for NotNan<T> {
    type Output = Self;

    #[inline]
    fn add(self, other: T) -> Self {
        NotNan::new(self.0 + other).expect("Addition resulted in NaN")
    }
}

/// Adds a float directly.
///
/// Panics if the provided value is NaN.
impl<T: FloatCore + Sum> Sum for NotNan<T> {
    fn sum<I: Iterator<Item = NotNan<T>>>(iter: I) -> Self {
        NotNan::new(iter.map(|v| v.0).sum()).expect("Sum resulted in NaN")
    }
}

impl<'a, T: FloatCore + Sum + 'a> Sum<&'a NotNan<T>> for NotNan<T> {
    #[inline]
    fn sum<I: Iterator<Item = &'a NotNan<T>>>(iter: I) -> Self {
        iter.cloned().sum()
    }
}

/// Subtracts a float directly.
///
/// Panics if the provided value is NaN or the computation results in NaN
impl<T: FloatCore> Sub<T> for NotNan<T> {
    type Output = Self;

    #[inline]
    fn sub(self, other: T) -> Self {

View on GitHub (pinned to 288d84d76e)