databendlabs/databend · error
Rem resulted in NaN
Error message
Rem resulted in NaN
What it means
The Rem impl for NotNan<T> computes self.0 % other and validates with NotNan::new, panicking with this message if the remainder is NaN. IEEE remainder is NaN for x % 0, inf % x, and NaN operands. This is the wrapper's fail-fast check keeping NaN out of ordered floats.
Solutions
- Validate before the op: `divisor.is_finite() && divisor != 0.0 && dividend.is_finite()`.
- Fall back to `NotNan::new(a.0 % b).ok()` and handle None (e.g. skip the value or use a default bucket).
- Ensure bucket-size config cannot be 0 and clamp upstream values so they never reach inf.
Example fix
// before
let bucket = notnan_value % bucket_size; // panics if bucket_size == 0
// after
let bucket = if bucket_size.is_finite() && bucket_size != 0.0 { notnan_value % bucket_size } else { notnan_value }; Defensive patterns
Strategy: validation
Validate before calling
fn can_rem(a: &NotNan<f64>, b: f64) -> bool {
b != 0.0 && b.is_finite() && a.0.is_finite()
} Type guard
fn is_valid_modulus(x: f64) -> bool { x != 0.0 && x.is_finite() } Try / catch
let bucket = std::panic::catch_unwind(|| notnan_value % bucket_size).ok();
Prevention
- Validate bucket/modulus config values are nonzero and finite at load time.
- Ensure the dividend cannot be inf (guard earlier arithmetic).
- Use NotNan::new(a.0 % b).ok() for fallible remainder computation.
When it happens
Trigger: Using `%` (std::ops::Rem<T> for NotNan<T>) with a divisor of 0.0, a dividend of ±inf, or a NaN `other` operand.
Common situations: Bucketing/binning values with a modulo computed from config that resolved to 0, or taking remainders of values that overflowed to infinity earlier in the pipeline.
Related errors
- Addition resulted in NaN
- Division resulted in NaN
- Multiplication resulted in NaN
- partial_cmp failed for non-NaN value
- Pow resulted in NaN
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/c7b9954e120ff8f5.
Report an issue: GitHub.
Appendix: source
Thrown at src/common/base/src/base/ordered_float.rs:1397
/// Panics if the provided value is NaN or the computation results in NaN
impl<T: FloatCore> Div<T> for NotNan<T> {
type Output = Self;
#[inline]
fn div(self, other: T) -> Self {
NotNan::new(self.0 / other).expect("Division resulted in NaN")
}
}
/// Calculates `%` with a float directly.
///
/// Panics if the provided value is NaN or the computation results in NaN
impl<T: FloatCore> Rem<T> for NotNan<T> {
type Output = Self;
#[inline]
fn rem(self, other: T) -> Self {
NotNan::new(self.0 % other).expect("Rem resulted in NaN")
}
}
macro_rules! impl_not_nan_binop {
($imp:ident, $method:ident, $assign_imp:ident, $assign_method:ident) => {
impl<T: FloatCore> $imp for NotNan<T> {
type Output = Self;
#[inline]
fn $method(self, other: Self) -> Self {
self.$method(other.0)
}
}
impl<T: FloatCore> $imp<&T> for NotNan<T> {
type Output = NotNan<T>;
#[inline]View on GitHub (pinned to 288d84d76e)