pola-rs/polars · error
should be f64 scalar
Error message
should be f64 scalar
What it means
The DecimalChunked aggregation helper rescales result scalars by dividing by 10^scale, and assumes the scalar carries an f64 value (as produced by mean-style aggregations). If the scalar holds another dtype, try_extract::<f64>() fails and it panics 'should be f64 scalar'. This is an internal invariant between decimal aggregations and their scalar outputs.
Source
Thrown at crates/polars-core/src/series/implementations/decimal.rs:43
fn apply_physical<T, F: Fn(&Int128Chunked) -> T>(&self, f: F) -> T {
f(self.0.physical())
}
fn scale_factor(&self) -> u128 {
10u128.pow(self.0.scale() as u32)
}
fn apply_scale(&self, mut scalar: Scalar) -> Scalar {
if scalar.is_null() {
return scalar;
}
debug_assert_eq!(scalar.dtype(), &DataType::Float64);
let v = scalar
.value()
.try_extract::<f64>()
.expect("should be f64 scalar");
scalar.update((v / self.scale_factor() as f64).into());
scalar
}
fn agg_helper<F: Fn(&Int128Chunked) -> Series>(&self, f: F, precision: usize) -> Series {
let agg_s = f(self.0.physical());
let scale = self.0.scale();
match agg_s.dtype() {
DataType::Int128 => {
let ca = agg_s.i128().unwrap();
let ca = ca.as_ref().clone();
ca.into_decimal_unchecked(precision, scale).into_series()
},
DataType::List(dtype) if matches!(dtype.as_ref(), DataType::Int128) => {
let dtype = self.0.dtype();
let ca = agg_s.list().unwrap();
let arr = ca.downcast_iter().next().unwrap();
// SAFETY: dtype is passed correctlyView on GitHub (pinned to 68506541d2)
Solutions
- Align all polars crates on one exact version (cargo update / lockfile pin) so decimal aggregation helpers match
- Upgrade polars to the latest release; decimal aggregation invariants are actively fixed
- As a workaround, cast decimals to Float64 before the aggregation, then re-cast if needed
Example fix
# before
pl.col("price").mean() # decimal mean path panics on mismatched versions
# after
pl.col("price").cast(pl.Float64).mean() # bypass decimal helper until upgraded Defensive patterns
Strategy: fallback
Validate before calling
fn is_decimal(s: &Series) -> bool {
matches!(s.dtype(), DataType::Decimal(_, _))
} Prevention
- Keep every polars-* crate on the same version via the lockfile
- Cast decimal columns to Float64 before aggregations when running mixed/older versions
- Pin the polars release in CI and add decimal aggregation regression tests
When it happens
Trigger: Aggregations over Decimal columns (mean, sum-then-normalize paths) where the aggregation returns a scalar whose dtype is not Float64 - typically from custom/user-defined aggregations plugged into the decimal path, or a mismatch between polars crate versions.
Common situations: Mixing polars-core and polars-lazy/plan versions so decimal aggregation helpers receive unexpected scalar types; custom plugin aggregations on decimal columns; encountered after upgrading one polars crate but not the others.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Dynamic MinMax is not yet implemented for {:?}
- only supported for scalars
- groups are slices not index
- groups are index not slices
- cross join filter holds no keys
AI-assisted analysis of pola-rs/polars@68506541d2 (2026-08-19).
Data as JSON: /api/errors/9a39e5b839f26c92.
Report an issue: GitHub.