pandas-dev/pandas · error · TypeError

Must provide 'func' or tuples of '(column, aggfunc).

Error message

Must provide 'func' or tuples of '(column, aggfunc).

What it means

Raised by reconstruct_func (apply.py:1946) as a TypeError when func is None and the kwargs do not form a valid relabeling/named-aggregation spec. reconstruct_func accepts either a real func (string/callable/list/dict) or kwargs that look like named aggregation (column, aggfunc) tuples / NamedAgg objects; if neither is present the user has effectively passed nothing actionable.

Source

Thrown at pandas/core/apply.py:1946

    relabeling = func is None and (
        is_multi_agg_with_relabel(**kwargs)
        or any(isinstance(v, NamedAgg) for v in kwargs.values())
    )

    columns: tuple[str, ...] | None = None
    order: npt.NDArray[np.intp] | None = None

    if not relabeling:
        if isinstance(func, list) and len(func) > len(set(func)):
            # GH 28426 will raise error if duplicated function names are used and
            # there is no reassigned name
            raise SpecificationError(
                "Function names must be unique if there is no new column names assigned"
            )
        if func is None:
            # nicer error message
            raise TypeError("Must provide 'func' or tuples of '(column, aggfunc).")

    if relabeling:
        normalization_needed = False
        # error: Incompatible types in assignment (expression has type
        # "MutableMapping[Hashable, list[Callable[..., Any] | str]]", variable has type
        # "Callable[..., Any] | str | list[Callable[..., Any] | str] |
        # MutableMapping[Hashable, Callable[..., Any] | str | list[Callable[..., Any] |
        # str]] | None")
        converted_kwargs = {}
        for key, val in kwargs.items():
            if isinstance(val, NamedAgg):
                column = val.column
                aggfunc = val.aggfunc
                if val.args or val.kwargs:
                    aggfunc = lambda x, func=aggfunc, a=val.args, kw=val.kwargs: func(
                        x, *a, **kw
                    )
            else:

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Pass a real func or named-aggregation kwargs: df.agg('sum'), df.agg({'a':'sum'}), or df.agg(out=('a','sum')).
  2. If the spec is built dynamically, guard against empty/None before calling agg and skip the call or supply a default.
  3. For named aggregation use the tuple form df.agg(new_name=(column, func)) or NamedAgg(column=..., aggfunc=...).

Example fix

// before
spec = None  # accidentally empty
df.agg(spec)
// after
df.agg('sum')
// or named
import pandas as pd
df.agg(total=pd.NamedAgg(column='a', aggfunc='sum'))
Defensive patterns

Strategy: validation

Validate before calling

if func is None and not kwargs:
    raise TypeError("agg requires a func or named-aggregation kwargs")

Type guard

def agg_has_spec(func, kwargs: dict) -> bool:
    return func is not None or bool(kwargs)

Try / catch

try:
    df.agg(func, **kwargs)
except TypeError as e:
    if "Must provide 'func'" in str(e):
        df.agg('sum')  # sensible default
    else:
        raise

Prevention

When it happens

Trigger: df.agg(None), df.agg(), or df.groupby('g').agg() with no positional func and no kwargs matching the named-aggregation shape. Triggered at apply.py:1944-1946 when func is None and the relabeling check at apply.py:1929-1932 returned False.

Common situations: Building the agg spec dynamically and ending up with an empty/None value; typo in the kwarg (e.g. df.agg(col=sum) without the tuple form); refactoring that stripped the positional arg; calling agg with a variable that evaluated to None.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/84844015fcad1abe. Report an issue: GitHub.