databendlabs/databend · error

Subtraction resulted in NaN

Error message

Subtraction resulted in NaN

What it means

The Sub impl for NotNan<T> computes self.0 - other and validates the result through NotNan::new, which panics with this message if the difference is NaN. NaN arises here from inf - inf or any NaN operand. The panic preserves the type's guarantee that no NaN NotNan ever exists.

Solutions

  1. Guard the subtraction: only subtract when both operands satisfy `is_finite()`.
  2. Use `NotNan::new(a.0 - b).ok()` and handle failure instead of the panicking operator.
  3. Reject or sanitize NaN/infinite inputs at ingestion with `NotNan::new(x)` at the API boundary.

Example fix

// before
let diff = notnan_a - raw_b; // panics when a and b are both inf
// after
let diff = if notnan_a.is_finite() && raw_b.is_finite() { NotNan::new(notnan_a.0 - raw_b).ok() } else { None };
Defensive patterns

Strategy: validation

Validate before calling

fn can_sub(a: &NotNan<f64>, b: f64) -> bool {
    a.is_finite() && b.is_finite()
}

Type guard

fn is_finite_f64(x: f64) -> bool { x.is_finite() }

Try / catch

let diff = std::panic::catch_unwind(|| notnan_a - raw_b).ok();

Prevention

When it happens

Trigger: Using `-` (std::ops::Sub<T> for NotNan<T>) when self is +inf/-inf and other is the same-signed infinity, or when `other` is a raw NaN float, or when self wraps a NaN produced via unsafe NotNan construction.

Common situations: Computing deltas between metrics that both overflowed to infinity (e.g. 1e308 * 10 differences), or subtracting parsed user input that was never validated as finite.

Related errors


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

Appendix: source

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

    }
}

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 {
        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")

View on GitHub (pinned to 288d84d76e)