{"record":{"id":"30dfd60d203d525a","repo":"databendlabs/databend","slug":"sum-resulted-in-nan","errorCode":null,"errorMessage":"Sum resulted in NaN","messagePattern":"Sum resulted in NaN","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/common/base/src/base/ordered_float.rs","lineNumber":1329,"sourceCode":"\n/// Adds a float directly.\n///\n/// Panics if the provided value is NaN or the computation results in NaN\nimpl<T: FloatCore> Add<T> for NotNan<T> {\n    type Output = Self;\n\n    #[inline]\n    fn add(self, other: T) -> Self {\n        NotNan::new(self.0 + other).expect(\"Addition resulted in NaN\")\n    }\n}\n\n/// Adds a float directly.\n///\n/// Panics if the provided value is NaN.\nimpl<T: FloatCore + Sum> Sum for NotNan<T> {\n    fn sum<I: Iterator<Item = NotNan<T>>>(iter: I) -> Self {\n        NotNan::new(iter.map(|v| v.0).sum()).expect(\"Sum resulted in NaN\")\n    }\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 {","sourceCodeStart":1311,"sourceCodeEnd":1347,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/common/base/src/base/ordered_float.rs#L1311-L1347","documentation":"The Sum impl for NotNan<T> folds the iterator's underlying floats with std's Sum and rewraps via NotNan::new. If the accumulated sum is NaN (any NaN element, or inf + -inf intermediate), NotNan::new panics with this message. The wrapper intentionally refuses to let NaN flow into ordered float collections.","triggerScenarios":"`iter.sum::<NotNan<f64>>()` where the iterator contains a NaN NotNan (constructible only via unsafe or prior bugs) or where the running sum becomes NaN through inf + -inf cancellation of infinite elements.","commonSituations":"Aggregating columns of computed values where some rows contain infinities from division by zero, so +inf and -inf sums cancel to NaN; also summing very large magnitudes that overflow to inf on both signs.","solutions":["Filter non-finite values before summing: `iter.filter(|v| v.is_finite()).sum()`.","Collect into f64, sum, and check: `NotNan::new(vals.iter().sum::<f64>()).ok()` with explicit NaN handling.","Fix upstream computations that emit inf (guard divisions, clamp overflow) before the sum."],"exampleFix":"// before\nlet total: NotNan<f64> = values.iter().copied().sum(); // panics on NaN result\n// after\nlet total: NotNan<f64> = values.iter().copied().filter(|v| v.is_finite()).sum();","handlingStrategy":"validation","validationCode":"fn safe_sum(vals: &[NotNan<f64>]) -> Option<NotNan<f64>> {\n    if vals.iter().all(|v| v.is_finite()) {\n        let raw: f64 = vals.iter().map(|v| v.0).sum();\n        NotNan::new(raw).ok()\n    } else { None }\n}","typeGuard":"fn all_finite(vals: &[NotNan<f64>]) -> bool { vals.iter().all(|v| v.is_finite()) }","tryCatchPattern":"let total = std::panic::catch_unwind(|| vals.iter().copied().sum::<NotNan<f64>>()).ok();","preventionTips":["Filter or reject non-finite elements before summing.","Sum in plain f64 with explicit NaN checks, then wrap once via NotNan::new.","Fix inf-producing computations (division by zero, overflow) upstream."],"tags":["rust","float","nan","sum","aggregation","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"}