{"record":{"id":"2b2861f2abc1a5ec","repo":"pandas-dev/pandas","slug":"cannot-perform-how-with-non-ordered-categorical","errorCode":null,"errorMessage":"Cannot perform {how} with non-ordered Categorical","messagePattern":"Cannot perform (.+?) with non-ordered Categorical","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/categorical.py","lineNumber":2876,"sourceCode":"        has_dropped_na: bool,\n        min_count: int,\n        ngroups: int,\n        ids: npt.NDArray[np.intp],\n        **kwargs,\n    ):\n        from pandas.core.groupby.ops import WrappedCythonOp\n\n        kind = WrappedCythonOp.get_kind_from_how(how)\n        op = WrappedCythonOp(how=how, kind=kind, has_dropped_na=has_dropped_na)\n\n        dtype = self.dtype\n        if how in [\"sum\", \"prod\", \"cumsum\", \"cumprod\", \"skew\", \"kurt\"]:\n            raise TypeError(f\"{dtype} type does not support {how} operations\")\n        if how in [\"min\", \"max\", \"rank\", \"idxmin\", \"idxmax\"] and not dtype.ordered:\n            # raise TypeError instead of NotImplementedError to ensure we\n            #  don't go down a group-by-group path, since in the empty-groups\n            #  case that would fail to raise\n            raise TypeError(f\"Cannot perform {how} with non-ordered Categorical\")\n        if how not in [\n            \"rank\",\n            \"any\",\n            \"all\",\n            \"first\",\n            \"last\",\n            \"min\",\n            \"max\",\n            \"idxmin\",\n            \"idxmax\",\n        ]:\n            if kind == \"transform\":\n                raise TypeError(f\"{dtype} type does not support {how} operations\")\n            raise TypeError(f\"{dtype} dtype does not support aggregation '{how}'\")\n\n        result_mask = None\n        mask = self.isna()\n        if how == \"rank\":","sourceCodeStart":2858,"sourceCodeEnd":2894,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/categorical.py#L2858-L2894","documentation":"Raised by Categorical._groupby_op when the aggregation is order-based (min, max, rank, idxmin, idxmax) but the categorical dtype is unordered. Min/max/rank require a total ordering; an unordered categorical defines only a label set, so these operations are undefined. The comment in source notes this is raised as TypeError deliberately to avoid a slower per-group path that would also fail.","triggerScenarios":"df.groupby('g')['cat'].min(), .max(), .rank(), .idxmin(), or .idxmax() on an unordered category column.","commonSituations":"A 'low/med/high' or 'cold/warm/hot' style column created without ordered=True; groupby pipelines that compute extrema or ranks on every categorical column.","solutions":["Make the column ordered: df['cat'] = df['cat'].cat.as_ordered() (or pd.Categorical(..., ordered=True) with explicit categories).","Use .first()/.last() instead of min/max if ordering is not meaningful.","Cast to the underlying value dtype and aggregate there."],"exampleFix":"// before\ndf.groupby('g')['cat'].min()  # TypeError: Cannot perform min with non-ordered Categorical\n\n// after\ndf['cat'] = df['cat'].cat.as_ordered()\ndf.groupby('g')['cat'].min()","handlingStrategy":"validation","validationCode":"ORDER_HOW = {'min','max','rank','idxmin','idxmax'}\ndef ensure_ordered_for_how(s, how):\n    import pandas as pd\n    if isinstance(s.dtype, pd.CategoricalDtype) and how in ORDER_HOW and not s.cat.ordered:\n        return s.cat.as_ordered()\n    return s","typeGuard":"import pandas as pd\nfrom typing import Any\n\ndef can_perform_order_op(obj: Any, how: str) -> bool:\n    dt = getattr(obj, 'dtype', None)\n    if isinstance(dt, pd.CategoricalDtype):\n        return dt.ordered or how not in {'min','max','rank','idxmin','idxmax'}\n    return True","tryCatchPattern":"try:\n    df.groupby('g')['cat'].min()\nexcept TypeError as e:\n    if 'non-ordered Categorical' in str(e):\n        df['cat'] = df['cat'].cat.as_ordered()\n    else:\n        raise","preventionTips":["Mark ordinal category columns ordered=True at creation.","Guard groupby min/max/rank with an ordered check on category columns."],"tags":["categorical","groupby","ordered"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}