pandas-dev/pandas · error · ValueError

Function did not transform

Error message

Function did not transform

What it means

Raised by DataFrame.transform / Series.transform when the user-supplied function returns a result that is not a same-index Series or DataFrame. Transform requires the output to have an identical index to the input so it can be placed back into the original shape; a scalar, an array, or a Series with a different index all violate that contract. Pandas raises (rather than silently broadcasting) so that silent shape mismatches do not corrupt downstream data. It is the second guard in transform, after the empty-result check.

Solutions

  1. If you want a scalar/reduced result, use `df.agg(func)` or `df.apply(func)` instead of `df.transform(func)`.
  2. If using a UDF, ensure it returns a Series with the SAME index as the input (e.g. operate elementwise: `df.transform(lambda s: s * 2)`).
  3. Avoid row-filtering operations inside transform; if you must filter, reindex back: `df.transform(lambda s: s.dropna().reindex(df.index))`.
  4. For a list of built-in methods, confirm the method is a transform (e.g. 'shift', 'rank', 'cumsum', 'fillna') rather than an aggregator ('mean', 'sum').

Example fix

// before
df.transform('mean')
df.transform(lambda s: s.dropna())
// after
df.agg('mean')
df.transform(lambda s: s * 2)
Defensive patterns

Strategy: validation

Validate before calling

def safe_transform(df_or_series, func):
    import pandas as pd
    # Probe on a tiny copy to verify shape contract before the real call.
    probe = df_or_series.head(2) if hasattr(df_or_series, 'head') else df_or_series
    res = probe.transform(func)
    if not res.index.equals(probe.index):
        raise ValueError('func does not preserve index; use agg/apply instead of transform')
    return df_or_series.transform(func)

Type guard

def is_transform_compatible(func, obj) -> bool:
    # A transform-compatible func returns a same-index Series/DataFrame.
    try:
        probe = obj.head(1) if hasattr(obj, 'head') else obj
        res = probe.transform(func)
        return res.index.equals(probe.index)
    except Exception:
        return False

Try / catch

try:
    result = df.transform(func)
except ValueError as e:
    if 'did not transform' in str(e):
        result = df.agg(func)  # fallback to aggregation semantics
    else:
        raise

Prevention

When it happens

Trigger: Calling `df.transform(func)` or `series.transform(func)` where `func` is a callable/string that returns: a scalar (e.g. `df.transform('mean')`), a list/array whose length differs from the index, a Series whose `.index` does not equal `df.index` (e.g. `df.transform(lambda s: s.dropna())`), or a non-NDFrame object. Also fires when a string method like 'mean' (an aggregator, not a transform) is passed.

Common situations: Developers conflate `transform` with `apply`/`agg` and pass a reducer such as 'mean', 'sum', 'count'. Or they pass a UDF that filters rows (dropna, drop_duplicates), changing the index. Or they return a numpy array of a different length than the input.

Related errors


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

Appendix: source

Thrown at pandas/core/apply.py:406

        try:
            result = self.transform_str_or_callable(func)
        except TypeError:
            raise
        except Exception as err:
            raise ValueError("Transform function failed") from err

        # Functions that transform may return empty Series/DataFrame
        # when the dtype is not appropriate
        if (
            isinstance(result, (ABCSeries, ABCDataFrame))
            and result.empty
            and not obj.empty
        ):
            raise ValueError("Transform function failed")
        if not isinstance(result, (ABCSeries, ABCDataFrame)) or not result.index.equals(
            obj.index
        ):
            raise ValueError("Function did not transform")

        return result

    def transform_dict_like(self, func) -> DataFrame:
        """
        Compute transform in the case of a dict-like func
        """

        obj = self.obj
        args = self.args
        kwargs = self.kwargs

        # transform is currently only for Series/DataFrame
        assert isinstance(obj, ABCNDFrame)

        if len(func) == 0:
            raise ValueError("No transform functions were provided")

View on GitHub (pinned to 3b7651241d)