{"record":{"id":"27273c1680cb2f6f","repo":"databendlabs/databend","slug":"multiplication-resulted-in-nan","errorCode":null,"errorMessage":"Multiplication resulted in NaN","messagePattern":"Multiplication resulted in NaN","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/common/base/src/base/ordered_float.rs","lineNumber":1360,"sourceCode":"/// 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\")\n    }\n}\n\nimpl<'a, T: FloatCore + Product + 'a> Product<&'a NotNan<T>> for NotNan<T> {\n    #[inline]\n    fn product<I: Iterator<Item = &'a NotNan<T>>>(iter: I) -> Self {\n        iter.cloned().product()\n    }\n}\n\n/// Divides a float directly.\n///","sourceCodeStart":1342,"sourceCodeEnd":1378,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/common/base/src/base/ordered_float.rs#L1342-L1378","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet scaled = notnan_weight * raw_factor; // 0 * inf panics\n// after\nlet scaled = if raw_factor.is_finite() { notnan_weight * raw_factor } else { notnan_weight };","handlingStrategy":"validation","validationCode":"fn can_mul(a: &NotNan<f64>, b: f64) -> bool {\n    !(a.0 == 0.0 && b.is_infinite()) && !(a.0.is_infinite() && b == 0.0) && b.is_finite()\n}","typeGuard":"fn is_finite_f64(x: f64) -> bool { x.is_finite() }","tryCatchPattern":"let scaled = std::panic::catch_unwind(|| notnan_w * raw_f).ok();","preventionTips":["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."],"tags":["rust","float","nan","multiplication","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"}