pandas-dev/pandas · error · ValueError

cannot perform both aggregation and transformation…

Error message

cannot perform both aggregation and transformation operations simultaneously

What it means

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.

Solutions

  1. Make the dict spec uniform: either all scalar-aggregators (`{'A': 'mean', 'B': 'sum'}`) or all list-aggregators (`{'A': ['mean'], 'B': ['sum']}`).
  2. Move transform-style functions to a separate `df.transform({...})` call.
  3. If a UDF result shape varies, force a consistent shape (e.g. wrap scalars into a 1-element list).

Example fix

// before
df.agg({'A': 'mean', 'B': ['mean', 'sum']})
// after
df.agg({'A': ['mean'], 'B': ['mean', 'sum']})
Defensive patterns

Strategy: validation

Validate before calling

def safe_dict_agg(df, spec):
    import pandas as pd
    # Normalize: every value must be a list (so all results are DataFrame-shaped) or all scalar.
    is_list_val = all(isinstance(v, (list, tuple)) for v in spec.values())
    is_scalar_val = all(not isinstance(v, (list, tuple)) for v in spec.values())
    if not (is_list_val or is_scalar_val):
        normalized = {k: (v if isinstance(v, (list, tuple)) else [v]) for k, v in spec.items()}
        return df.agg(normalized)
    return df.agg(spec)

Type guard

def dict_spec_is_uniform(spec) -> bool:
    vals = list(spec.values())
    return all(isinstance(v, (list, tuple)) for v in vals) or all(not isinstance(v, (list, tuple)) for v in vals)

Try / catch

try:
    out = df.agg(spec)
except ValueError as e:
    if 'aggregation and transformation' in str(e):
        normalized = {k: (v if isinstance(v, (list, tuple)) else [v]) for k, v in spec.items()}
        out = df.agg(normalized)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/c28fd4be7f6bf5d9. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/apply.py:689

                keys_to_use = result_index
                results = result_data

            if selected_obj.ndim == 2:
                # keys are columns, so we can preserve names
                ktu = Index(keys_to_use)
                ktu._set_names(selected_obj.columns.names)
                keys_to_use = ktu

            axis: AxisInt = 0 if isinstance(obj, ABCSeries) else 1
            result = concat(
                results,
                axis=axis,
                keys=keys_to_use,
                sort=False,
            )
        elif any(is_ndframe):
            # There is a mix of NDFrames and scalars
            raise ValueError(
                "cannot perform both aggregation "
                "and transformation operations "
                "simultaneously"
            )
        else:
            from pandas import Series

            # we have a list of scalars
            # GH 36212 use name only if obj is a series
            if obj.ndim == 1:
                obj = cast("Series", obj)
                name = obj.name
            else:
                name = None

            result = Series(result_data, index=result_index, name=name)

        return result

View on GitHub (pinned to 3b7651241d)