{"record":{"id":"27a1fd4568d95f08","repo":"pandas-dev/pandas","slug":"periods-must-be-an-integer","errorCode":null,"errorMessage":"periods must be an integer","messagePattern":"periods must be an integer","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/algorithms.py","lineNumber":1521,"sourceCode":"    ----------\n    arr : ndarray or ExtensionArray\n    n : int\n        number of periods\n    axis : {0, 1}\n        axis to shift on\n    stacklevel : int, default 3\n        The stacklevel for the lost dtype warning.\n\n    Returns\n    -------\n    shifted\n    \"\"\"\n\n    # added a check on the integer value of period\n    # see https://github.com/pandas-dev/pandas/issues/56607\n    if not lib.is_integer(n):\n        if not (is_float(n) and n.is_integer()):\n            raise ValueError(\"periods must be an integer\")\n        n = int(n)\n    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__}__\"):","sourceCodeStart":1503,"sourceCodeEnd":1539,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/algorithms.py#L1503-L1539","documentation":"The diff() and shift() functions require the periods argument (n) to be an integer. This check accepts Python ints, numpy integers, and floats that are whole numbers (e.g., 3.0), but rejects fractional floats, strings, None, and other non-integer types. The check was added in GH#56607 to catch invalid period values early before they cause confusing downstream behavior.","triggerScenarios":"Calling df.diff(n) or s.shift(n) where n is a float like 1.5, a string like \"2\", None, or NaN. Passing a periods value computed from a calculation that can produce non-integer results (e.g., division). Using a variable that is dynamically typed and may hold a non-integer.","commonSituations":"Computing shift periods from a formula (e.g., len(df) / num_groups) that yields a float, then passing it directly to diff(). Receiving a periods value from user input or configuration as a string. Passing np.nan as periods when a computed window size is undefined.","solutions":["Explicitly cast n to int: df.diff(int(n)).","Validate n is integer-valued before calling: if isinstance(n, float) and not n.is_integer(): raise ValueError(...).","Ensure computed period values use integer division (//) rather than float division (/)."],"exampleFix":"# before\nperiods = len(df) / num_groups  # may produce a float\ndf.diff(periods)\n\n# after\nperiods = len(df) // num_groups  # integer division\ndf.diff(periods)","handlingStrategy":"validation","validationCode":"def safe_diff(series_or_df, periods, axis=0):\n    if isinstance(periods, float):\n        if not periods.is_integer():\n            raise ValueError(f\"periods must be integer, got {periods}\")\n        periods = int(periods)\n    elif not isinstance(periods, (int, np.integer)):\n        raise ValueError(f\"periods must be integer, got {type(periods).__name__}\")\n    return series_or_df.diff(periods, axis=axis)","typeGuard":"def is_valid_periods(n) -> bool:\n    if isinstance(n, (int, np.integer)):\n        return True\n    if isinstance(n, float) and n.is_integer():\n        return True\n    return False","tryCatchPattern":"try:\n    result = df.diff(periods)\nexcept ValueError as e:\n    if \"periods must be an integer\" in str(e):\n        result = df.diff(int(periods))\n    else:\n        raise","preventionTips":["Always cast periods to int before calling diff or shift.","Use integer division (//) when computing periods from lengths.","Validate dynamically-computed periods with isinstance(n, (int, np.integer))."],"tags":["pandas","diff","shift","periods","valueerror","integer-validation"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}