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
- Check `(base >= 0.0 || exponent.fract() == 0.0)` and both operands finite before calling pow.
- Use fallible `NotNan::new(base.0.pow(exp)).ok()` and handle the NaN case explicitly.
- 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
- Only apply fractional exponents to non-negative bases.
- Check base and exponent are finite before pow.
- Use a checked helper (NotNan::new(...).ok()) for pow in generic code.
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
- Addition resulted in NaN
- Division resulted in NaN
- Multiplication resulted in NaN
- partial_cmp failed for non-NaN value
- Product resulted in NaN
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)