{"record":{"id":"0e05416b11dad914","repo":"pandas-dev/pandas","slug":"nested-renamer-is-not-supported","errorCode":null,"errorMessage":"nested renamer is not supported","messagePattern":"nested renamer is not supported","errorType":"exception","errorClass":"SpecificationError","httpStatus":null,"severity":"error","filePath":"pandas/core/apply.py","lineNumber":794,"sourceCode":"        self, how: str, obj: DataFrame | Series, func: AggFuncTypeDict\n    ) -> AggFuncTypeDict:\n        \"\"\"\n        Handler for dict-like argument.\n\n        Ensures that necessary columns exist if obj is a DataFrame, and\n        that a nested renamer is not passed. Also normalizes to all lists\n        when values consists of a mix of list and non-lists.\n        \"\"\"\n        assert how in (\"apply\", \"agg\", \"transform\")\n\n        # Can't use func.values(); wouldn't work for a Series\n        if (\n            how == \"agg\"\n            and isinstance(obj, ABCSeries)\n            and any(is_list_like(v) for _, v in func.items())\n        ) or (any(is_dict_like(v) for _, v in func.items())):\n            # GH 15931 - deprecation of renaming keys\n            raise SpecificationError(\"nested renamer is not supported\")\n\n        if obj.ndim != 1:\n            # Check for missing columns on a frame\n            from pandas import Index\n\n            cols = Index(list(func.keys())).difference(obj.columns, sort=True)\n            if len(cols) > 0:\n                # GH 58474\n                raise KeyError(f\"Label(s) {list(cols)} do not exist\")\n\n        aggregator_types = (list, tuple, dict)\n\n        # if we have a dict of any non-scalars\n        # eg. {'A' : ['mean']}, normalize all to\n        # be list-likes\n        # Cannot use func.values() because arg may be a Series\n        if any(isinstance(x, aggregator_types) for _, x in func.items()):\n            new_func: AggFuncTypeDict = {}","sourceCodeStart":776,"sourceCodeEnd":812,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/apply.py#L776-L812","documentation":"Raised by `normalize_dictlike_arg` as a `SpecificationError` when the dict-like func passed to agg/apply/transform contains nested dict values (a 'nested renamer'), or when a Series.agg is given list-like values. Since GH 15931 pandas no longer supports the old renaming syntax `{'new_name': {'old_col': 'mean'}}`; the dict shape must map columns directly to functions/lists-of-functions.","triggerScenarios":"`df.agg({'result': {'A': 'mean'}})` (nested dict), `series.agg({'x': ['mean', 'sum']})` (list values on a Series), or any dict whose values are themselves dict-like. Fires for how in ('apply','agg','transform') when the nested condition matches.","commonSituations":"Legacy pandas code using the pre-0.20 / pre-0.25 renaming-dict syntax; copy-pasted StackOverflow answers from old pandas versions; attempting to rename-and-aggregate in one shot.","solutions":["Flatten the spec: rename columns first (`df.rename(columns=...)` or `df = df.rename(...)`), then call `.agg({col: [funcs]})`.","For Series.agg, use a list of funcs without a dict: `series.agg(['mean', 'sum'])`.","If you want named outputs from a list, use named aggregations or rename the result Series afterwards."],"exampleFix":"// before\ndf.agg({'result': {'A': 'mean'}})\n// after\ndf[['A']].agg({'A': 'mean'}).rename('result')","handlingStrategy":"validation","validationCode":"def flatten_agg_spec(df, spec):\n    import collections.abc as cabc\n    # Reject nested dicts (renamers); require flat column -> func/list-of-funcs.\n    for k, v in spec.items():\n        if isinstance(v, cabc.Mapping):\n            raise ValueError(f'nested renamer at key {k!r}; flatten the spec')\n    return spec","typeGuard":"def is_flat_agg_spec(spec) -> bool:\n    import collections.abc as cabc\n    return all(not isinstance(v, cabc.Mapping) for v in spec.values())","tryCatchPattern":"from pandas.errors import SpecificationError\ntry:\n    out = df.agg(spec)\nexcept SpecificationError as e:\n    if 'nested renamer' in str(e):\n        # flatten by pre-renaming columns\n        out = df.rename(columns={k: list(v)[0] for k, v in spec.items()}).agg(...)\n    else:\n        raise","preventionTips":["Never use the legacy {'new_name': {'old_col': func}} syntax.","Rename columns explicitly before agg.","Add a spec-validation step in pipelines that ingest user-supplied agg dicts."],"tags":["pandas","agg","renamer","specificationerror","legacy"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}