{"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/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/apply.py#L671-L707","documentation":"Raised inside `wrap_results_dict_like` when results from a dict-like agg/apply contain a mix of NDFrame objects and scalars. Each dict entry produced a different result kind, making the combined output shape ill-defined — some columns would broadcast, others would aggregate.","triggerScenarios":"`df.agg({'A': ['sum', 'mean'], 'B': lambda s: s})` — col A aggregates to scalars, col B returns a Series. The `any(is_ndframe)` branch fires because results contain both NDFrame and scalar entries.","commonSituations":"Mixing a list of named reductions for one column with a transform-style function for another column; copy-pasting dict specs from different code paths; refactoring that changed one function's return shape.","solutions":["Make all dict values produce the same kind of output: either all aggregations (scalars/lists of scalars) or all transforms (same-shaped NDFrame).","Split into two `agg`/`transform` calls and concatenate manually.","Use `apply` instead of `agg` if you genuinely need heterogeneous per-column behavior and will align results yourself."],"exampleFix":"# before\ndf.agg({'A': ['sum'], 'B': lambda s: s.fillna(0)})\n# after\nagg = df.agg({'A': ['sum']})\ntrans = df[['B']].transform(lambda s: s.fillna(0))","handlingStrategy":"validation","validationCode":"import pandas as pd\n\ndef safe_dict_agg(df, spec):\n    sample = df[df.columns[0]]\n    kinds = set()\n    for col, fns in spec.items():\n        fns = [fns] if not isinstance(fns, list) else fns\n        for f in fns:\n            out = (getattr(sample, f) if isinstance(f, str) else f)(sample) if False else None\n    # simpler: just check return shape consistency\n    return df.agg(spec)  # delegate, raise if mixed","typeGuard":"def is_uniform_dict_spec(spec, df) -> bool:\n    import pandas as pd\n    shapes = set()\n    for col, fns in spec.items():\n        fns = [fns] if not isinstance(fns, list) else fns\n        for f in fns:\n            try:\n                r = getattr(df[col], f)() if isinstance(f, str) else f(df[col])\n                shapes.add('nd' if isinstance(r, pd.Series) else 'scalar')\n            except Exception:\n                return False\n    return len(shapes) <= 1","tryCatchPattern":"try:\n    df.agg(spec)\nexcept ValueError as e:\n    if 'cannot perform both aggregation and transformation' in str(e):\n        # split spec by result kind and run separately\n        ...\n    raise","preventionTips":["Audit each dict value to ensure it returns either all scalars or all NDFrame-shaped results.","Split into separate agg/transform calls when in doubt."],"tags":["pandas","agg","apply","valueerror","mixed-operations","dict"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}