pola-rs/polars · error

comparing categoricals with different Categories is not…

Error message

comparing categoricals with different Categories is not supported through AnyValue

What it means

AnyValue::eq_missing refuses to compare two Categorical values whose category mappings are different Arc allocations (Arc::ptr_eq fails). The Hash impl for AnyValue hashes the raw physical index, so comparing values from different Categories/mappings would give wrong equality results. Instead of silently returning a wrong answer, the method panics via unimplemented!().

Solutions

  1. Cast one or both columns to a common mapping before comparing: `col.cast(DataType::Categorical(None, CategoricalOrdering::default()))` or use `.to_physical()` (u32) comparison
  2. Use the global string cache (pl.StringCache() / set_string_cache) so all categoricals share one rev-map
  3. Compare the underlying string representations instead (cast to Utf8/Str before the comparison)
  4. Restructure the operation to avoid cross-Series AnyValue comparison, e.g. compare via join on string keys

Example fix

// before: comparing categoricals from two independently built Series
let a = Series::new("a", ["x", "y"]).unwrap().cast(&DataType::Categorical(None, Default::default())).unwrap();
let b = Series::new("b", ["x", "z"]).unwrap().cast(&DataType::Categorical(None, Default::default())).unwrap();
let _ = a.equal(&b)?; // may hit the unimplemented!() via AnyValue comparisons
// after: share a mapping via the global string cache
let _guard = polars::datatypes::PlStringRefCache::insert();
let a = Series::new("a", ["x", "y"]).unwrap().cast(&DataType::Categorical(None, Default::default())).unwrap();
let b = Series::new("b", ["x", "z"]).unwrap().cast(&DataType::Categorical(None, Default::default())).unwrap();
let _ = a.equal(&b)?;
Defensive patterns

Strategy: validation

Validate before calling

fn same_categorical_mapping(a: &AnyValue, b: &AnyValue) -> bool {
    match (a, b) {
        (AnyValue::Categorical(_, l), AnyValue::Categorical(_, r)) => Arc::ptr_eq(l, r),
        _ => false,
    }
}
// call eq_missing only if same_categorical_mapping(&x, &y)

Prevention

When it happens

Trigger: Calling AnyValue::eq_missing (directly or via AnyValue::eq / tot_eq) with two AnyValue::Categorical variants built from different CategoricalRevMapping instances — e.g. categorical values taken from two separate DataFrames/Series that each created their own category mapping, or mixing a global mapping with a local one.

Common situations: Joining or comparing columns of dtype Categorical that were constructed independently (each Series gets its own rev-map), concatenating categorical frames, or hand-assembling AnyValues from different Series in expression predicates and filter/when-then contexts.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/042bf1203e38ff3e. Report an issue: GitHub.

Appendix: source

Thrown at crates/polars-core/src/datatypes/any_value.rs:1283

            (String(l), String(r)) => l == r,
            (Binary(l), Binary(r)) => l == r,
            #[cfg(feature = "dtype-time")]
            (Time(l), Time(r)) => *l == *r,
            #[cfg(all(feature = "dtype-datetime", feature = "dtype-date"))]
            (Date(l), Date(r)) => *l == *r,
            #[cfg(all(feature = "dtype-datetime", feature = "dtype-date"))]
            (Datetime(l, tul, tzl), Datetime(r, tur, tzr)) => {
                *l == *r && *tul == *tur && tzl == tzr
            },
            (List(l), List(r)) => l == r,
            #[cfg(feature = "dtype-map")]
            (Map(l), Map(r)) => l == r,
            #[cfg(feature = "dtype-categorical")]
            (Categorical(cat_l, map_l), Categorical(cat_r, map_r)) => {
                if !Arc::ptr_eq(map_l, map_r) {
                    // We can't support this because our Hash impl directly hashes the index. If you
                    // add support for this we must change the Hash impl.
                    unimplemented!(
                        "comparing categoricals with different Categories is not supported through AnyValue"
                    );
                }

                cat_l == cat_r
            },
            #[cfg(feature = "dtype-categorical")]
            (Enum(cat_l, map_l), Enum(cat_r, map_r)) => {
                if !Arc::ptr_eq(map_l, map_r) {
                    // We can't support this because our Hash impl directly hashes the index. If you
                    // add support for this we must change the Hash impl.
                    unimplemented!(
                        "comparing enums with different FrozenCategories is not supported through AnyValue"
                    );
                }

                cat_l == cat_r
            },

View on GitHub (pinned to fe841f959e)