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
- Guard the subtraction: only subtract when both operands satisfy `is_finite()`.
- Use `NotNan::new(a.0 - b).ok()` and handle failure instead of the panicking operator.
- 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
- Verify both operands are finite before subtracting (avoids inf - inf).
- Sanitize parsed/user floats at the boundary with NotNan::new.
- Use checked helpers returning Option instead of the panicking operator.
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
- partial_cmp failed for non-NaN value
- Addition resulted in NaN
- Sum resulted in NaN
- Multiplication resulted in NaN
- Product resulted in NaN
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)