databendlabs/databend · error

Pow resulted in NaN

Error message

Pow resulted in NaN

What it means

This is the Pow impl for NotNan<inner> with an owned rhs (from the impl_not_nan_pow macro): it computes `<$inner>::pow(self.0, rhs)` and passes the result to NotNan::new, panicking with this message if the power result is NaN. powf/powi yields NaN for cases like negative base with fractional exponent, or inf/NaN operands.

Solutions

  1. Check `(base >= 0.0 || exponent.fract() == 0.0)` and both operands finite before calling pow.
  2. Use fallible `NotNan::new(base.0.pow(exp)).ok()` and handle the NaN case explicitly.
  3. For fractional powers of negatives, use complex arithmetic or clamp/skip the value.

Example fix

// before
let root = notnan_base.pow(0.5); // panics for negative base
// after
let root = if **base >= 0.0 { base.pow(0.5) } else { None };
Defensive patterns

Strategy: validation

Validate before calling

fn can_pow(base: &NotNan<f64>, exp: f64) -> bool {
    exp.is_finite() && (**base >= 0.0 || exp.fract() == 0.0)
}

Type guard

fn is_safe_pow_base(x: f64, exp: f64) -> bool { x >= 0.0 || exp.fract() == 0.0 }

Try / catch

let r = std::panic::catch_unwind(|| notnan_base.pow(0.5)).ok();

Prevention

When it happens

Trigger: Calling `pow` (or the `**`/Pow operator) on NotNan<f32/f64> where the base is negative and the exponent is fractional (e.g. (-2.0).pow(0.5)), or where base/exponent combine to NaN via inf - inf semantics in powf.

Common situations: Root/sqrt-like computations (0.5 exponent) applied to values that can be negative, or exponentiating values that previously overflowed to inf.

Related errors


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

Appendix: source

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

            }
        }
    };
}

impl_not_nan_binop! {Add, add, AddAssign, add_assign}
impl_not_nan_binop! {Sub, sub, SubAssign, sub_assign}
impl_not_nan_binop! {Mul, mul, MulAssign, mul_assign}
impl_not_nan_binop! {Div, div, DivAssign, div_assign}
impl_not_nan_binop! {Rem, rem, RemAssign, rem_assign}

// Will panic if NaN value is return from the operation
macro_rules! impl_not_nan_pow {
    ($inner:ty, $rhs:ty) => {
        impl Pow<$rhs> for NotNan<$inner> {
            type Output = NotNan<$inner>;
            #[inline]
            fn pow(self, rhs: $rhs) -> NotNan<$inner> {
                NotNan::new(<$inner>::pow(self.0, rhs)).expect("Pow resulted in NaN")
            }
        }

        impl<'a> Pow<&'a $rhs> for NotNan<$inner> {
            type Output = NotNan<$inner>;
            #[inline]
            fn pow(self, rhs: &'a $rhs) -> NotNan<$inner> {
                NotNan::new(<$inner>::pow(self.0, *rhs)).expect("Pow resulted in NaN")
            }
        }

        impl<'a> Pow<$rhs> for &'a NotNan<$inner> {
            type Output = NotNan<$inner>;
            #[inline]
            fn pow(self, rhs: $rhs) -> NotNan<$inner> {
                NotNan::new(<$inner>::pow(self.0, rhs)).expect("Pow resulted in NaN")
            }
        }

View on GitHub (pinned to 288d84d76e)