{"record":{"id":"6e09afef0cf8532f","repo":"pandas-dev/pandas","slug":"offset-offset-did-not-increment-date","errorCode":null,"errorMessage":"Offset {offset} did not increment date","messagePattern":"Offset (.+?) did not increment date","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/datetimes.py","lineNumber":3273,"sourceCode":"\n    start = cast(\"Timestamp\", start)\n    end = cast(\"Timestamp\", end)\n\n    cur = start\n    if offset.n >= 0:\n        while cur <= end:\n            yield cur\n\n            if cur == end:\n                # GH#24252 avoid overflows by not performing the addition\n                # in offset.apply unless we have to\n                break\n\n            # faster than cur + offset\n            next_date = offset._apply(cur)\n            next_date = next_date.as_unit(unit)\n            if next_date <= cur:\n                raise ValueError(f\"Offset {offset} did not increment date\")\n            cur = next_date\n    else:\n        while cur >= end:\n            yield cur\n\n            if cur == end:\n                # GH#24252 avoid overflows by not performing the addition\n                # in offset.apply unless we have to\n                break\n\n            # faster than cur + offset\n            next_date = offset._apply(cur)\n            next_date = next_date.as_unit(unit)\n            if next_date >= cur:\n                raise ValueError(f\"Offset {offset} did not decrement date\")\n            cur = next_date\n","sourceCodeStart":3255,"sourceCodeEnd":3290,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/datetimes.py#L3255-L3290","documentation":"Raised inside the date_range generator loop (datetime_to_seq) when applying `offset._apply(cur)` to the current timestamp does not advance it (next_date <= cur for positive offsets, or next_date >= cur for negative). This protects against infinite loops from pathological offsets whose n is zero or whose apply is a no-op for the given input.","triggerScenarios":"Calling `pd.date_range(start, end, freq=<custom offset that does not advance>)` with a custom DateOffset subclass whose `_apply` returns the same or earlier timestamp. Using an offset with `n=0` in a context that bypasses the n==0 fast path. Also reachable with offsets that round/truncate backward (e.g. some semi-month-end offsets near boundaries).","commonSituations":"User-defined DateOffset with a buggy `_apply`. Built-in offsets with `n=0` (e.g. `pd.offsets.Day(0)`). Edge cases in custom business calendars. Offsets that snap to month-end applied at month-end where the snap returns the same date.","solutions":["Audit the offset: ensure `offset._apply(ts) > ts` for positive-n offsets on all relevant inputs.","Avoid `n=0` offsets in date_range — they cannot produce a sequence; filter them out upstream.","Switch to a built-in offset that is known to advance (e.g. `pd.offsets.Day(1)`).","If using a custom calendar, add an explicit advance in `_apply` and unit-test it across month/year boundaries."],"exampleFix":"// before\nrng = pd.date_range(start, end, freq=pd.offsets.Day(0))\n\n// after\nrng = pd.date_range(start, end, freq=pd.offsets.Day(1))","handlingStrategy":"validation","validationCode":"import pandas as pd\n\ndef offset_advances(offset, ts):\n    nxt = offset._apply(ts)\n    return nxt > ts if offset.n >= 0 else nxt < ts\n\ndef safe_date_range(start, end, freq):\n    if getattr(freq, 'n', 1) == 0:\n        raise ValueError('offset with n=0 cannot generate a range')\n    return pd.date_range(start=start, end=end, freq=freq)","typeGuard":"def offset_is_progressing(offset, ts) -> bool:\n    try:\n        nxt = offset._apply(ts)\n    except Exception:\n        return False\n    return nxt > ts if offset.n >= 0 else nxt < ts","tryCatchPattern":"try:\n    rng = pd.date_range(start=start, end=end, freq=freq)\nexcept ValueError as e:\n    if 'did not increment date' in str(e) or 'did not decrement date' in str(e):\n        raise ValueError(f'Offset {freq} is a no-op; choose an advancing offset') from e\n    raise","preventionTips":["Reject n=0 offsets before calling date_range.","Unit-test custom DateOffset._apply across month/year boundaries.","Prefer built-in offsets over hand-rolled ones."],"tags":["datetime","date-range","offset","frequency","infinite-loop-guard"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}