{"record":{"id":"48b332abcc28cf19","repo":"pandas-dev/pandas","slug":"cannot-diff-type-arr-name-on-axis-axis","errorCode":null,"errorMessage":"cannot diff {type(arr).__name__} on axis={axis}","messagePattern":"cannot diff (.+?) on axis=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/algorithms.py","lineNumber":1541,"sourceCode":"    na = np.nan\n    dtype = arr.dtype\n\n    is_bool = is_bool_dtype(dtype)\n    if is_bool:\n        op = operator.xor\n    else:\n        op = operator.sub\n\n    if isinstance(dtype, NumpyEADtype):\n        # NumpyExtensionArray cannot necessarily hold shifted versions of itself.\n        arr = arr.to_numpy()\n        dtype = arr.dtype\n\n    if not isinstance(arr, np.ndarray):\n        # i.e ExtensionArray\n        if hasattr(arr, f\"__{op.__name__}__\"):\n            if axis >= arr.ndim:\n                raise ValueError(f\"cannot diff {type(arr).__name__} on axis={axis}\")\n            return op(arr, arr.shift(n))\n        else:\n            raise TypeError(\n                f\"{type(arr).__name__} has no 'diff' method. \"\n                \"Convert to a suitable dtype prior to calling 'diff'.\"\n            )\n\n    is_timedelta = False\n    if arr.dtype.kind in \"mM\":\n        dtype = np.int64\n        arr = arr.view(\"i8\")\n        na = iNaT\n        is_timedelta = True\n\n    elif is_bool:\n        # We have to cast in order to be able to hold np.nan\n        dtype = np.object_\n","sourceCodeStart":1523,"sourceCodeEnd":1559,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/algorithms.py#L1523-L1559","documentation":"Raised by pandas.core.algorithms.diff when differencing an ExtensionArray that does support differencing (it defines the subtraction operator) but the requested axis is out of range (axis >= arr.ndim). For a 1-D ExtensionArray only axis 0 is valid.","triggerScenarios":"Calling diff on a 1-D ExtensionArray (e.g. a nullable/integer or pyarrow-backed array) with axis=1; forwarding a DataFrame axis=1 down to a per-column ExtensionArray diff.","commonSituations":"Generic code that passes axis through to diff without checking the array's ndim; switching a column's dtype to an ExtensionArray (nullable Int64, ArrowDtype) and reusing axis=1 logic.","solutions":["Use axis=0 for 1-D ExtensionArrays.","Perform the diff at the DataFrame level (df.diff(axis=1)) rather than on a single ExtensionArray column.","Check arr.ndim before choosing the axis."],"exampleFix":"# before\narr = pd.array([1, 2, 3], dtype='Int64')\npd.core.algorithms.diff(arr, 1, axis=1)\n# after\npd.core.algorithms.diff(arr, 1, axis=0)","handlingStrategy":"validation","validationCode":"import numpy as np\n\ndef safe_diff_arr(arr, n, axis=0):\n    if axis >= np.asarray(arr).ndim:\n        raise ValueError(f'axis {axis} invalid for ndim {np.asarray(arr).ndim}')\n    return pd.core.algorithms.diff(arr, n, axis=axis)","typeGuard":"def axis_in_range(arr, axis) -> bool:\n    return 0 <= axis < getattr(arr, 'ndim', 1)","tryCatchPattern":null,"preventionTips":["Use axis=0 for 1-D ExtensionArrays.","Diff at the DataFrame level for axis=1 rather than per-column arrays.","Check arr.ndim before choosing axis."],"tags":["diff","axis","extension-array","validation"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}