{"record":{"id":"fd40ee485718ad78","repo":"pandas-dev/pandas","slug":"start-and-end-must-have-same-freq","errorCode":null,"errorMessage":"start and end must have same freq","messagePattern":"start and end must have same freq","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/period.py","lineNumber":1534,"sourceCode":"        raise ValueError(\n            \"Of the three parameters: start, end, and periods, \"\n            \"exactly two must be specified\"\n        )\n\n    if freq is not None:\n        freq = to_offset(freq, is_period=True)\n        mult = freq.n\n\n    if start is not None:\n        start = Period(start, freq)\n    if end is not None:\n        end = Period(end, freq)\n\n    is_start_per = isinstance(start, Period)\n    is_end_per = isinstance(end, Period)\n\n    if is_start_per and is_end_per and start.freq != end.freq:\n        raise ValueError(\"start and end must have same freq\")\n    if start is NaT or end is NaT:\n        raise ValueError(\"start and end must not be NaT\")\n\n    if freq is None:\n        if is_start_per:\n            freq = start.freq\n        elif is_end_per:\n            freq = end.freq\n        else:  # pragma: no cover\n            raise ValueError(\"Could not infer freq from start/end\")\n        mult = freq.n\n\n    if periods is not None:\n        periods = periods * mult\n        if start is None:\n            data = np.arange(\n                end.ordinal - periods + mult, end.ordinal + 1, mult, dtype=np.int64\n            )","sourceCodeStart":1516,"sourceCodeEnd":1552,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/period.py#L1516-L1552","documentation":"Raised inside _get_ordinal_range (the engine behind period_range and PeriodIndex construction) when both `start` and `end` are Period objects but carry different frequencies. pandas cannot lay out a contiguous ordinal range whose endpoints live on incompatible grids, so it refuses rather than silently picking one freq. The check fires only when no explicit `freq` argument overrides the Periods' own frequencies.","triggerScenarios":"Calling period_range(start=Period('2020','A-DEC'), end=Period('2020Q1','Q')) or constructing a PeriodIndex/period_range with two Period endpoints whose .freq differ and with freq=None. Because Period(end, freq) preserves end's own freq when freq is None, the mismatch surfaces here.","commonSituations":"Mixing annual and quarterly endpoints copied from different columns; passing a start from one df and an end inferred from another without normalizing freq; refactors that drop the explicit freq= kwarg and rely on the Period objects.","solutions":["Pass an explicit freq= to period_range so both endpoints are re-grounded to it: period_range(start, end, freq='Q').","Normalize both endpoints to the same freq before calling: start = start.asfreq('Q'); end = end.asfreq('Q').","If the endpoints are strings, pass freq and let pandas parse both against it instead of constructing Periods yourself."],"exampleFix":"// before\npd.period_range(start=pd.Period('2020','A-DEC'), end=pd.Period('2020Q1','Q'))\n// after\npd.period_range(start='2020', end='2020Q1', freq='Q')","handlingStrategy":"validation","validationCode":"import pandas as pd\nfrom pandas import Period\n\ndef safe_period_range(start, end, freq=None):\n    s = Period(start, freq) if not isinstance(start, Period) else start\n    e = Period(end, freq) if not isinstance(end, Period) else end\n    if freq is None and s.freq != e.freq:\n        freq = s.freq  # or raise a clear error\n    return pd.period_range(start=start, end=end, freq=freq)","typeGuard":"def same_freq_period_pair(start, end) -> bool:\n    return (\n        isinstance(start, pd.Period)\n        and isinstance(end, pd.Period)\n        and start.freq == end.freq\n    )","tryCatchPattern":"try:\n    rng = pd.period_range(start=start, end=end, freq=freq)\nexcept ValueError as e:\n    if 'must have same freq' in str(e):\n        rng = pd.period_range(start=start, end=end, freq=start.freq)\n    else:\n        raise","preventionTips":["Always pass an explicit freq= when both start and end are Period objects.","Normalize endpoints with .asfreq() before constructing the range.","Add a unit test asserting period_range inputs share a frequency."],"tags":["pandas","period","period-range","frequency","dtype-validation"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}