databendlabs/databend · error
Multiplication resulted in NaN
Error message
Multiplication resulted in NaN
What it means
The Mul impl for NotNan<T> multiplies self.0 by a raw T and passes the product through NotNan::new, which panics with this message if the product is NaN. Multiplication yields NaN from 0 * inf, 0 * -inf, or any NaN operand. The panic is the wrapper's invariant enforcement.
Solutions
- Check `is_finite()` on both operands before multiplying; skip or substitute 0/1 for degenerate cases.
- Replace the operator with fallible `NotNan::new(a.0 * b).ok()` and branch on the result.
- Clamp or guard upstream division/overflow that produces infinite operands before they reach this multiplication.
Example fix
// before
let scaled = notnan_weight * raw_factor; // 0 * inf panics
// after
let scaled = if raw_factor.is_finite() { notnan_weight * raw_factor } else { notnan_weight }; Defensive patterns
Strategy: validation
Validate before calling
fn can_mul(a: &NotNan<f64>, b: f64) -> bool {
!(a.0 == 0.0 && b.is_infinite()) && !(a.0.is_infinite() && b == 0.0) && b.is_finite()
} Type guard
fn is_finite_f64(x: f64) -> bool { x.is_finite() } Try / catch
let scaled = std::panic::catch_unwind(|| notnan_w * raw_f).ok();
Prevention
- Reject 0 * inf combinations: check zeros and infinities on both operands.
- Clamp values that can overflow to inf before they enter products.
- Prefer NotNan::new(a.0 * b).ok() in code paths with unvalidated inputs.
When it happens
Trigger: Using `*` (std::ops::Mul<T> for NotNan<T>) where one operand underflows to zero and the other is infinite (0.0 * inf), or where the raw `other` argument is NaN.
Common situations: Scaling weights in numeric code where a coefficient became infinite due to earlier overflow (e.g. 1/0 normalization) while another factor is exactly 0; also multiplying by unvalidated parsed floats.
Related errors
- partial_cmp failed for non-NaN value
- Addition resulted in NaN
- Sum resulted in NaN
- Subtraction resulted in NaN
- Product resulted in NaN
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/27273c1680cb2f6f.
Report an issue: GitHub.
Appendix: source
Thrown at src/common/base/src/base/ordered_float.rs:1360
/// 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 {
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.
///View on GitHub (pinned to 288d84d76e)