{"record":{"id":"249f19766e8cbd26","repo":"pandas-dev/pandas","slug":"function-did-not-transform","errorCode":null,"errorMessage":"Function did not transform","messagePattern":"Function did not transform","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/apply.py","lineNumber":406,"sourceCode":"        try:\n            result = self.transform_str_or_callable(func)\n        except TypeError:\n            raise\n        except Exception as err:\n            raise ValueError(\"Transform function failed\") from err\n\n        # Functions that transform may return empty Series/DataFrame\n        # when the dtype is not appropriate\n        if (\n            isinstance(result, (ABCSeries, ABCDataFrame))\n            and result.empty\n            and not obj.empty\n        ):\n            raise ValueError(\"Transform function failed\")\n        if not isinstance(result, (ABCSeries, ABCDataFrame)) or not result.index.equals(\n            obj.index\n        ):\n            raise ValueError(\"Function did not transform\")\n\n        return result\n\n    def transform_dict_like(self, func) -> DataFrame:\n        \"\"\"\n        Compute transform in the case of a dict-like func\n        \"\"\"\n\n        obj = self.obj\n        args = self.args\n        kwargs = self.kwargs\n\n        # transform is currently only for Series/DataFrame\n        assert isinstance(obj, ABCNDFrame)\n\n        if len(func) == 0:\n            raise ValueError(\"No transform functions were provided\")\n","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/apply.py#L388-L424","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["If you want a scalar/reduced result, use `df.agg(func)` or `df.apply(func)` instead of `df.transform(func)`.","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)`).","Avoid row-filtering operations inside transform; if you must filter, reindex back: `df.transform(lambda s: s.dropna().reindex(df.index))`.","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')."],"exampleFix":"// before\ndf.transform('mean')\ndf.transform(lambda s: s.dropna())\n// after\ndf.agg('mean')\ndf.transform(lambda s: s * 2)","handlingStrategy":"validation","validationCode":"def safe_transform(df_or_series, func):\n    import pandas as pd\n    # Probe on a tiny copy to verify shape contract before the real call.\n    probe = df_or_series.head(2) if hasattr(df_or_series, 'head') else df_or_series\n    res = probe.transform(func)\n    if not res.index.equals(probe.index):\n        raise ValueError('func does not preserve index; use agg/apply instead of transform')\n    return df_or_series.transform(func)","typeGuard":"def is_transform_compatible(func, obj) -> bool:\n    # A transform-compatible func returns a same-index Series/DataFrame.\n    try:\n        probe = obj.head(1) if hasattr(obj, 'head') else obj\n        res = probe.transform(func)\n        return res.index.equals(probe.index)\n    except Exception:\n        return False","tryCatchPattern":"try:\n    result = df.transform(func)\nexcept ValueError as e:\n    if 'did not transform' in str(e):\n        result = df.agg(func)  # fallback to aggregation semantics\n    else:\n        raise","preventionTips":["Treat transform as elementwise-only; route any reducer to agg/apply.","Never filter rows (dropna, head) inside a transform UDF.","Unit-test UDFs against a 2-row probe asserting the index is preserved."],"tags":["pandas","transform","shape-mismatch","valueerror"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}