{"record":{"id":"2b3e3d08a68a3b51","repo":"pytorch/pytorch","slug":"cannot-preserve-first-class-dimensions-with-keepdi","errorCode":null,"errorMessage":"cannot preserve first-class dimensions with keepdim=True","messagePattern":"cannot preserve first-class dimensions with keepdim=True","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"functorch/dim/_wrap.py","lineNumber":72,"sourceCode":"        def wrapped_func(*args: Any, **kwargs: Any) -> Any:\n            return self.wrapper_implementation(self, *args, **kwargs)\n\n        # Copy metadata using functools.update_wrapper for just __name__ and __doc__\n        functools.update_wrapper(\n            wrapped_func, self.orig, assigned=(\"__name__\",), updated=()\n        )\n        wrapped_func.__doc__ = self.doc\n\n        return wrapped_func\n\n\ndef _wrap_dim(dim: Any, ndim: int, keepdim: bool = False) -> DimEntry:\n    \"\"\"Convert single dimension specification to DimEntry object.\"\"\"\n    from . import Dim\n\n    if isinstance(dim, Dim):\n        if keepdim:\n            raise ValueError(\"cannot preserve first-class dimensions with keepdim=True\")\n        return DimEntry(dim)\n    elif isinstance(dim, int):\n        i = dim\n        while i >= 0:\n            i -= ndim\n        return DimEntry(i)\n    else:\n        return DimEntry()\n\n\ndef _wrap_dims(dim: Any, ndim: int, keepdim: bool = False) -> list[DimEntry]:\n    \"\"\"Convert dimension specification to list of DimEntry objects.\"\"\"\n    de = _wrap_dim(dim, ndim, keepdim)\n    result = []\n    if not de.is_none():\n        result.append(de)\n    else:\n        for d in dim:","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/pytorch/pytorch/blob/dcd2ecae775af66439b7ede4e7a82540b058c59c/functorch/dim/_wrap.py#L54-L90","documentation":"Thrown by `_wrap_dim` in functorch/dim `_wrap.py`. When a dim specification is a first-class `Dim` object and the caller requested `keepdim=True`, the reduction wrapper raises: a named first-class dimension cannot be 'kept' as a size-1 axis, because it would no longer index the original dim.","triggerScenarios":"Calling a wrapped reduction (e.g. `t.sum(d, keepdim=True)` in the dims API) where `d` is a `Dim` object rather than an int.","commonSituations":"Porting existing `keepdim=True` reduction code to first-class dims; passing dim objects from `dims('...')` while keeping the old keepdim habit.","solutions":["Drop `keepdim=True` when reducing over a Dim object; named dims handle broadcasting via the dim itself","If you need keepdim semantics, reduce over the positional int index (`t.sum(t.dims.index(d), keepdim=True)`) instead of the Dim","Refactor downstream code so it does not rely on the kept size-1 axis"],"exampleFix":"# before\ns = t.sum(d, keepdim=True)  # d is a Dim -> ValueError\n\n# after\ns = t.sum(d)  # first-class dims do not support keepdim","handlingStrategy":"validation","validationCode":"from functorch.dim import Dim\n\ndef check_reduce_args(dims, keepdim):\n    if keepdim and any(isinstance(d, Dim) for d in (dims if isinstance(dims, (list, tuple)) else [dims])):\n        raise ValueError(\"first-class dims cannot be used with keepdim=True\")","typeGuard":null,"tryCatchPattern":"try:\n    s = t.sum(d, keepdim=True)\nexcept ValueError as e:\n    if \"cannot preserve first-class dimensions\" in str(e):\n        s = t.sum(d)  # retry without keepdim\n    else:\n        raise","preventionTips":["Default to keepdim=False in dims-based code","Centralize reductions in a helper that strips keepdim for Dim arguments"],"tags":["functorch","dims","reduction","keepdim"],"backgroundTag":null,"analyzedSha":"dcd2ecae775af66439b7ede4e7a82540b058c59c","analyzedAt":"2026-08-14T19:21:26.615Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}