{"record":{"id":"0eba3987b75cf738","repo":"databendlabs/databend","slug":"subtraction-resulted-in-nan","errorCode":null,"errorMessage":"Subtraction resulted in NaN","messagePattern":"Subtraction resulted in NaN","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/common/base/src/base/ordered_float.rs","lineNumber":1348,"sourceCode":"    }\n}\n\nimpl<'a, T: FloatCore + Sum + 'a> Sum<&'a NotNan<T>> for NotNan<T> {\n    #[inline]\n    fn sum<I: Iterator<Item = &'a NotNan<T>>>(iter: I) -> Self {\n        iter.cloned().sum()\n    }\n}\n\n/// Subtracts a float directly.\n///\n/// Panics if the provided value is NaN or the computation results in NaN\nimpl<T: FloatCore> Sub<T> for NotNan<T> {\n    type Output = Self;\n\n    #[inline]\n    fn sub(self, other: T) -> Self {\n        NotNan::new(self.0 - other).expect(\"Subtraction resulted in NaN\")\n    }\n}\n\n/// Multiplies a float directly.\n///\n/// Panics if the provided value is NaN or the computation results in NaN\nimpl<T: FloatCore> Mul<T> for NotNan<T> {\n    type Output = Self;\n\n    #[inline]\n    fn mul(self, other: T) -> Self {\n        NotNan::new(self.0 * other).expect(\"Multiplication resulted in NaN\")\n    }\n}\n\nimpl<T: FloatCore + Product> Product for NotNan<T> {\n    fn product<I: Iterator<Item = NotNan<T>>>(iter: I) -> Self {\n        NotNan::new(iter.map(|v| v.0).product()).expect(\"Product resulted in NaN\")","sourceCodeStart":1330,"sourceCodeEnd":1366,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/common/base/src/base/ordered_float.rs#L1330-L1366","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet diff = notnan_a - raw_b; // panics when a and b are both inf\n// after\nlet diff = if notnan_a.is_finite() && raw_b.is_finite() { NotNan::new(notnan_a.0 - raw_b).ok() } else { None };","handlingStrategy":"validation","validationCode":"fn can_sub(a: &NotNan<f64>, b: f64) -> bool {\n    a.is_finite() && b.is_finite()\n}","typeGuard":"fn is_finite_f64(x: f64) -> bool { x.is_finite() }","tryCatchPattern":"let diff = std::panic::catch_unwind(|| notnan_a - raw_b).ok();","preventionTips":["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."],"tags":["rust","float","nan","subtraction","panic"],"backgroundTag":"nan-arithmetic-panic","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}