databendlabs/databend · error
Product resulted in NaN
Error message
Product resulted in NaN
What it means
The Product impl for NotNan<T> folds the iterator's floats with std's Product and rewraps with NotNan::new, panicking with this message if the product is NaN. A NaN product occurs when any factor is NaN or when a zero factor meets an infinite intermediate product (0 * inf).
Solutions
- Validate all factors with `is_finite()` before folding; filter or short-circuit degenerate products.
- Compute in f64 and wrap fallibly: `NotNan::new(vals.iter().product::<f64>()).ok()` with explicit NaN handling.
- Use logs/stable transforms for large products to avoid inf intermediates that later cancel against zeros.
Example fix
// before
let p: NotNan<f64> = factors.iter().copied().product(); // 0 * inf panics
// after
let p = if factors.iter().any(|v| !v.is_finite() || **v == 0.0) { None } else { Some(factors.iter().copied().product::<NotNan<f64>>()) }; Defensive patterns
Strategy: validation
Validate before calling
fn safe_product(vals: &[NotNan<f64>]) -> Option<NotNan<f64>> {
let mut acc = 1.0f64;
for v in vals {
acc *= v.0;
if acc.is_nan() { return None; }
}
NotNan::new(acc).ok()
} Type guard
fn all_finite_nonzero_ok(vals: &[NotNan<f64>]) -> bool { vals.iter().all(|v| v.is_finite()) } Try / catch
let p = std::panic::catch_unwind(|| vals.iter().copied().product::<NotNan<f64>>()).ok();
Prevention
- Track the running product and bail out early if it becomes inf or NaN.
- Filter NaN/zeros when infinite factors are possible.
- Use log-space accumulation for large products to avoid inf intermediates.
When it happens
Trigger: `iter.product::<NotNan<f64>>()` where the running product overflows to inf and a later factor is 0.0, or where any factor is NaN (only reachable through unsafe NotNan construction or raw-value paths).
Common situations: Computing joint probabilities or compounded rates where underflow/overflow to 0/inf mixes with exact zeros; also product-reductions over sensor readings containing NaN sourced from upstream division by zero.
Related errors
- Sum resulted in NaN
- partial_cmp failed for non-NaN value
- Addition resulted in NaN
- Subtraction resulted in NaN
- Multiplication resulted in NaN
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/102b128912dd249b.
Report an issue: GitHub.
Appendix: source
Thrown at src/common/base/src/base/ordered_float.rs:1366
NotNan::new(self.0 - other).expect("Subtraction resulted in NaN")
}
}
/// Multiplies a float directly.
///
/// Panics if the provided value is NaN or the computation results in NaN
impl<T: FloatCore> Mul<T> for NotNan<T> {
type Output = Self;
#[inline]
fn mul(self, other: T) -> Self {
NotNan::new(self.0 * other).expect("Multiplication resulted in NaN")
}
}
impl<T: FloatCore + Product> Product for NotNan<T> {
fn product<I: Iterator<Item = NotNan<T>>>(iter: I) -> Self {
NotNan::new(iter.map(|v| v.0).product()).expect("Product resulted in NaN")
}
}
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 {View on GitHub (pinned to 288d84d76e)