{"record":{"id":"466b9f2a8563e508","repo":"pola-rs/polars","slug":"describe-categorical-only-works-on-categorical-c","errorCode":null,"errorMessage":"`describe_categorical` only works on categorical columns","messagePattern":"`describe_categorical` only works on categorical columns","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/interchange/column.py","lineNumber":78,"sourceCode":"    def describe_categorical(self) -> CategoricalDescription:\n        \"\"\"\n        Description of the categorical data type of the column.\n\n        Raises\n        ------\n        TypeError\n            If the data type of the column is not categorical.\n        \"\"\"\n        dtype = self._col.dtype\n        if isinstance(dtype, Categorical):\n            categories = self._col.unique().drop_nulls().cast(String)\n            is_ordered = False\n        elif isinstance(dtype, Enum):\n            categories = dtype.categories\n            is_ordered = True\n        else:\n            msg = \"`describe_categorical` only works on categorical columns\"\n            raise TypeError(msg)\n\n        return {\n            \"is_ordered\": is_ordered,\n            \"is_dictionary\": True,\n            \"categories\": PolarsColumn(categories, allow_copy=self._allow_copy),\n        }\n\n    @property\n    def describe_null(self) -> tuple[ColumnNullType, int | None]:\n        \"\"\"Description of the null representation the column uses.\"\"\"\n        if self.null_count == 0:\n            return ColumnNullType.NON_NULLABLE, None\n        else:\n            return ColumnNullType.USE_BITMASK, 0\n\n    @property\n    def null_count(self) -> int:\n        \"\"\"The number of null elements.\"\"\"","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/interchange/column.py#L60-L96","documentation":"Raised by PolarsColumn.describe_categorical in the interchange protocol when the column's dtype is neither Categorical nor Enum. The method exists specifically to expose category metadata, so numeric/String/temporal columns are rejected with a TypeError.","triggerScenarios":"Calling describe_categorical() on an interchange column backed by String, Int64, or any non-categorical dtype; interchange consumers that unconditionally query categorical metadata for dictionary-encoded columns marked via the data kind flags; iterating columns and calling describe_categorical based on is_dictionary heuristics.","commonSituations":"Writing a generic interchange consumer that assumes any object/string column is dictionary-encoded; converting polars data for libraries expecting dictionary encoding; schema drift where a column that used to be Categorical arrives as String.","solutions":["Guard the call: only invoke describe_categorical when the dtype is Categorical or Enum","Cast beforehand if dictionary semantics are wanted: df.with_columns(pl.col('s').cast(pl.Categorical))","In consumers, rely on the interchange dtype kind (CATEGORICAL) rather than assuming string columns are categorical"],"exampleFix":"// before\ninfo = interchange_col.describe_categorical()  # on a String column\n// after\nfrom polars.datatypes import Categorical, Enum\nif isinstance(interchange_col._col.dtype, (Categorical, Enum)):\n    info = interchange_col.describe_categorical()","handlingStrategy":"type-guard","validationCode":"from polars.datatypes import Categorical, Enum\n\nif isinstance(column._col.dtype, (Categorical, Enum)):\n    info = column.describe_categorical()","typeGuard":"def is_categorical_column(col) -> bool:\n    from polars.datatypes import Categorical, Enum\n    return isinstance(col._col.dtype, (Categorical, Enum))","tryCatchPattern":"try:\n    info = col.describe_categorical()\nexcept TypeError:\n    info = None  # not dictionary-encoded; treat as plain values","preventionTips":["Gate describe_categorical behind a dtype check in consumer code","Use the interchange dtype kind flags to decide, not column names"],"tags":["polars","interchange-protocol","categorical","type-validation"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}