pola-rs/polars · error

from_cats_and_dtype called on non-categorical type

Error message

from_cats_and_dtype called on non-categorical type

What it means

Type-safety assertion inside from_cats_and_dtype: the supplied `dtype` is not a Categorical or Enum DataType, so constructing a CategoricalChunked from physical category ids against it is invalid. This is an internal/API-misuse guard — callers must pass a categorical-family dtype.

Source

Thrown at crates/polars-core/src/chunked_array/logical/categorical.rs:80

    pub fn uses_lexical_ordering(&self) -> bool {
        !self.is_enum()
    }

    pub fn full_null_with_dtype(name: PlSmallStr, length: usize, dtype: DataType) -> Self {
        let phys =
            ChunkedArray::<<T as PolarsCategoricalType>::PolarsPhysical>::full_null(name, length);
        unsafe { Self::from_cats_and_dtype_unchecked(phys, dtype) }
    }

    /// Create a [`CategoricalChunked`] from a physical array and dtype.
    ///
    /// Checks that all the category ids are valid, mapping invalid ones to nulls.
    pub fn from_cats_and_dtype(
        mut cat_ids: ChunkedArray<T::PolarsPhysical>,
        dtype: DataType,
    ) -> Self {
        let (DataType::Enum(_, mapping) | DataType::Categorical(_, mapping)) = &dtype else {
            panic!("from_cats_and_dtype called on non-categorical type")
        };
        assert!(dtype.cat_physical().ok() == Some(T::physical()));

        unsafe {
            let mut invariants_violated = false;
            let mut validity = BitmapBuilder::new();
            for arr in cat_ids.downcast_iter_mut() {
                validity.reserve(arr.len());
                if arr.has_nulls() {
                    for opt_cat_id in arr.iter() {
                        if let Some(cat_id) = opt_cat_id {
                            validity.push_unchecked(mapping.cat_to_str(cat_id.as_cat()).is_some());
                        } else {
                            validity.push_unchecked(false);
                        }
                    }
                } else {
                    for cat_id in arr.values_iter() {

View on GitHub (pinned to 5d8ebabf11)

Solutions

  1. Call `from_cats_and_dtype` only on a Categorical/Enum chunked array; check the dtype before calling.
  2. Cast the series to Categorical first if that is the intended type.
Defensive patterns

Strategy: validation

When it happens

Trigger: This panic/expect fires when execution reaches an unguarded state described by: "from_cats_and_dtype called on non-categorical type". Typical triggers: unsupported dtype or feature-gated code path reached at runtime, invalid user input or environment variable value, calling API methods in the wrong order or on mismatched types, or data (lengths, offsets, ranges) violating the function's preconditions.

Common situations: Encountered when input data or configuration does not meet the preconditions of the throwing code path ("from_cats_and_dtype called on non-categorical type"). Common cases: missing Cargo feature flags, mismatched dtypes/lengths between arrays or series, out-of-range temporal values, malformed environment variables, or operations on unsupported/complex nested types.


AI-assisted analysis of pola-rs/polars@5d8ebabf11 (2026-08-19). Data as JSON: /api/errors/18a65b57aae50601. Report an issue: GitHub.