{"record":{"id":"c28fd4be7f6bf5d9","repo":"pandas-dev/pandas","slug":"cannot-perform-both-aggregation-and-transformation","errorCode":null,"errorMessage":"cannot perform both aggregation and transformation operations simultaneously","messagePattern":"cannot perform both aggregation and transformation operations simultaneously","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/apply.py","lineNumber":689,"sourceCode":"                keys_to_use = result_index\n                results = result_data\n\n            if selected_obj.ndim == 2:\n                # keys are columns, so we can preserve names\n                ktu = Index(keys_to_use)\n                ktu._set_names(selected_obj.columns.names)\n                keys_to_use = ktu\n\n            axis: AxisInt = 0 if isinstance(obj, ABCSeries) else 1\n            result = concat(\n                results,\n                axis=axis,\n                keys=keys_to_use,\n                sort=False,\n            )\n        elif any(is_ndframe):\n            # There is a mix of NDFrames and scalars\n            raise ValueError(\n                \"cannot perform both aggregation \"\n                \"and transformation operations \"\n                \"simultaneously\"\n            )\n        else:\n            from pandas import Series\n\n            # we have a list of scalars\n            # GH 36212 use name only if obj is a series\n            if obj.ndim == 1:\n                obj = cast(\"Series\", obj)\n                name = obj.name\n            else:\n                name = None\n\n            result = Series(result_data, index=result_index, name=name)\n\n        return result","sourceCodeStart":671,"sourceCodeEnd":707,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/apply.py#L671-L707","documentation":"Raised inside `wrap_results_dict_like` when the per-column results of a dict-like agg/transform contain a MIX of NDFrames and scalars. A consistent dict-spec must either reduce every column to a scalar (-> Series result) or transform every column to an NDFrame (-> DataFrame result); mixing the two is ambiguous and pandas refuses to guess.","triggerScenarios":"Calling `df.agg({'A': 'mean', 'B': ['mean', 'sum']})` where one column reduces to a scalar and another produces a DataFrame, or `df.agg({'A': 'mean', 'B': lambda s: s})` (mean is a reducer, the lambda is a transform). The `any(is_ndframe)` branch fires when at least one but not all results are NDFrames.","commonSituations":"Dict specs where some columns get a single aggregator (scalar result) and others get a list of aggregators (DataFrame result), or mixing string aggregators with elementwise UDFs.","solutions":["Make the dict spec uniform: either all scalar-aggregators (`{'A': 'mean', 'B': 'sum'}`) or all list-aggregators (`{'A': ['mean'], 'B': ['sum']}`).","Move transform-style functions to a separate `df.transform({...})` call.","If a UDF result shape varies, force a consistent shape (e.g. wrap scalars into a 1-element list)."],"exampleFix":"// before\ndf.agg({'A': 'mean', 'B': ['mean', 'sum']})\n// after\ndf.agg({'A': ['mean'], 'B': ['mean', 'sum']})","handlingStrategy":"validation","validationCode":"def safe_dict_agg(df, spec):\n    import pandas as pd\n    # Normalize: every value must be a list (so all results are DataFrame-shaped) or all scalar.\n    is_list_val = all(isinstance(v, (list, tuple)) for v in spec.values())\n    is_scalar_val = all(not isinstance(v, (list, tuple)) for v in spec.values())\n    if not (is_list_val or is_scalar_val):\n        normalized = {k: (v if isinstance(v, (list, tuple)) else [v]) for k, v in spec.items()}\n        return df.agg(normalized)\n    return df.agg(spec)","typeGuard":"def dict_spec_is_uniform(spec) -> bool:\n    vals = list(spec.values())\n    return all(isinstance(v, (list, tuple)) for v in vals) or all(not isinstance(v, (list, tuple)) for v in vals)","tryCatchPattern":"try:\n    out = df.agg(spec)\nexcept ValueError as e:\n    if 'aggregation and transformation' in str(e):\n        normalized = {k: (v if isinstance(v, (list, tuple)) else [v]) for k, v in spec.items()}\n        out = df.agg(normalized)\n    else:\n        raise","preventionTips":["Normalize dict-spec values to lists before agg to guarantee uniform shape.","Audit any dict-spec mixing single strings and lists.","Run a probe on `df.head(2).agg(spec)` to catch the mismatch early."],"tags":["pandas","agg","dict-like","mixed-result","valueerror"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}