pola-rs/polars · error

not implemented

Error message

not implemented

What it means

mean_list_numerical (the fast path for list.mean()) dispatches on the inner dtype and only enumerates integer/float primitives from i8 through f64; the catch-all arm is a bare unimplemented!(). Because is_primitive_numeric() includes Float16, a List(Float16) column selects this fast path and then panics - Float16 is the realistic gap.

Source

Thrown at crates/polars-ops/src/chunked_array/list/sum_mean.rs:207

        .downcast_iter()
        .map(|arr| {
            let offsets = arr.offsets().as_slice();
            let values = arr.values().as_ref();

            match inner_type {
                Int8 => dispatch_mean::<i8, f64>(values, offsets, arr.validity()),
                Int16 => dispatch_mean::<i16, f64>(values, offsets, arr.validity()),
                Int32 => dispatch_mean::<i32, f64>(values, offsets, arr.validity()),
                Int64 => dispatch_mean::<i64, f64>(values, offsets, arr.validity()),
                Int128 => dispatch_mean::<i128, f64>(values, offsets, arr.validity()),
                UInt8 => dispatch_mean::<u8, f64>(values, offsets, arr.validity()),
                UInt16 => dispatch_mean::<u16, f64>(values, offsets, arr.validity()),
                UInt32 => dispatch_mean::<u32, f64>(values, offsets, arr.validity()),
                UInt64 => dispatch_mean::<u64, f64>(values, offsets, arr.validity()),
                UInt128 => dispatch_mean::<u128, f64>(values, offsets, arr.validity()),
                Float32 => dispatch_mean::<f32, f32>(values, offsets, arr.validity()),
                Float64 => dispatch_mean::<f64, f64>(values, offsets, arr.validity()),
                _ => unimplemented!(),
            }
        })
        .collect::<Vec<_>>();

    Series::try_from((ca.name().clone(), chunks)).unwrap()
}

pub(super) fn mean_with_nulls(ca: &ListChunked) -> Series {
    match ca.inner_dtype() {
        #[cfg(feature = "dtype-f16")]
        DataType::Float16 => {
            let out: Float16Chunked = ca
                .apply_amortized_generic(|s| {
                    use num_traits::FromPrimitive;

                    s.and_then(|s| s.as_ref().mean().map(|v| pf16::from_f64(v).unwrap()))
                })
                .with_name(ca.name().clone());

View on GitHub (pinned to df599052da)

Solutions

  1. Cast the list column's inner dtype to Float32 before taking the mean: pl.col("x").cast(pl.List(pl.Float32)).list.mean()
  2. Enable/verify the dtype-f16 aware slow path by using sum/mean fallbacks that handle nulls (mean_with_nulls handles Float16 when nulls are present)
  3. Upgrade polars - Float16 support in list aggregations is progressively being filled in

Example fix

# before
df.select(pl.col("f16_lists").list.mean())  # List(Float16) -> panic

# after
df.select(
    pl.col("f16_lists").cast(pl.List(pl.Float32)).list.mean()
)
Defensive patterns

Strategy: validation

Validate before calling

def list_mean_supported(s: pl.Series) -> bool:
    inner = s.dtype.inner if isinstance(s.dtype, pl.List) else None
    return inner is not None and inner != pl.Float16 and not isinstance(inner, pl.Float16)

Type guard

def mean_ready_list(s: pl.Series) -> pl.Series:
    if isinstance(s.dtype, pl.List) and s.dtype.inner == pl.Float16:
        return s.cast(pl.List(pl.Float32))
    return s

Prevention

When it happens

Trigger: Calling .mean() on a Series/expression of dtype List(Float16): df.select(pl.col("f16_lists").list.mean()).

Common situations: Half-precision embeddings or ML feature lists stored as f16 to save memory, then aggregated with list.mean() without casting.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/c2f1c8d6adba002e. Report an issue: GitHub.