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
- Check the divisor: ensure `other.is_finite() && other != 0.0` (and numerator not inf) before dividing.
- Use fallible construction `NotNan::new(a.0 / b).ok()` and handle the degenerate case explicitly.
- 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
- Always check divisor != 0.0 and is_finite() before dividing.
- Handle the 0/0 case with an explicit default or Option return.
- Keep counts/normalizers as integers until the final division.
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
- Addition resulted in NaN
- Multiplication resulted in NaN
- partial_cmp failed for non-NaN value
- Pow resulted in NaN
- Product resulted in NaN
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)