databendlabs/databend · error

Division resulted in NaN

Error message

Division resulted in NaN

What it means

The Div impl for NotNan<T> divides self.0 by a raw T and validates via NotNan::new, panicking with this message if the quotient is NaN. IEEE division produces NaN for 0/0 and inf/inf (and any NaN operand); ordinary x/0 gives inf, which is allowed here. The panic upholds the no-NaN invariant.

Solutions

  1. Check the divisor: ensure `other.is_finite() && other != 0.0` (and numerator not inf) before dividing.
  2. Use fallible construction `NotNan::new(a.0 / b).ok()` and handle the degenerate case explicitly.
  3. Return a default (e.g. 0 or Option) for degenerate 0/0 ratios instead of performing the division.

Example fix

// before
let ratio = notnan_count / total; // 0/0 panics
// after
let ratio = if total != 0.0 && total.is_finite() { notnan_count / total } else { NotNan::new(0.0).unwrap() };
Defensive patterns

Strategy: validation

Validate before calling

fn can_div(a: &NotNan<f64>, b: f64) -> bool {
    b != 0.0 && b.is_finite() && !(a.0.is_infinite())
}

Type guard

fn is_valid_divisor(x: f64) -> bool { x != 0.0 && x.is_finite() }

Try / catch

let ratio = std::panic::catch_unwind(|| notnan_count / total).ok();

Prevention

When it happens

Trigger: Using `/` (std::ops::Div<T> for NotNan<T>) where both operands are zero (0.0 / 0.0), both are infinite with the same sign, or `other` is NaN.

Common situations: Normalizing by a count that is 0 (0/0), computing ratios of two metrics that both overflowed to inf, or dividing by parsed input that was never checked as finite/nonzero.

Related errors


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

Appendix: source

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

    }
}

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

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

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

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

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

macro_rules! impl_not_nan_binop {
    ($imp:ident, $method:ident, $assign_imp:ident, $assign_method:ident) => {
        impl<T: FloatCore> $imp for NotNan<T> {

View on GitHub (pinned to 288d84d76e)