pandas-dev/pandas · error · ValueError

start and end must have same freq

Error message

start and end must have same freq

What it means

Raised by _get_ordinal_range when both start and end are Period objects but their .freq attributes differ. Period ranges are uniform-frequency; mixing endpoints of different frequencies has no well-defined result.

Solutions

  1. Align both endpoints with .asfreq(target_freq) before passing them.
  2. Pass freq= explicitly and use plain strings/timestamps for start/end so pandas harmonizes them.
  3. Normalize at the source: construct both Periods with the same freq literal.

Example fix

# before
pd.period_range(pd.Period('2020','A'), pd.Period('2020-03','M'), freq='M')
# after
start = pd.Period('2020','A').asfreq('M')
pd.period_range(start, pd.Period('2020-03','M'), freq='M')
Defensive patterns

Strategy: validation

Validate before calling

from pandas import Period

def endpoints_share_freq(start, end) -> bool:
    if isinstance(start, Period) and isinstance(end, Period):
        return start.freq == end.freq
    return True

Type guard

from pandas import Period

def both_periods_same_freq(start, end) -> bool:
    return (
        not (isinstance(start, Period) and isinstance(end, Period))
        or start.freq == end.freq
    )

Try / catch

try:
    pr = pd.period_range(start=start, end=end, freq=freq)
except ValueError as e:
    if 'same freq' in str(e) and isinstance(start, pd.Period):
        pr = pd.period_range(start=start.asfreq(freq), end=end.asfreq(freq), freq=freq)
    else:
        raise

Prevention

When it happens

Trigger: pd.period_range(start=pd.Period('2020','A'), end=pd.Period('2020-03','M')); passing two Period scalars of different freq to PeriodIndex start/end.

Common situations: Pulling start/end Period values from two different sources that were constructed with different freqs; user-supplied dates parsed with different defaults; migration where one literal changed.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/fd40ee485718ad78. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/arrays/period.py:1537

        raise ValueError(
            "Of the three parameters: start, end, and periods, "
            "exactly two must be specified"
        )

    if freq is not None:
        freq = to_offset(freq, is_period=True)
        mult = freq.n

    if start is not None:
        start = Period(start, freq)
    if end is not None:
        end = Period(end, freq)

    is_start_per = isinstance(start, Period)
    is_end_per = isinstance(end, Period)

    if is_start_per and is_end_per and start.freq != end.freq:
        raise ValueError("start and end must have same freq")
    if start is NaT or end is NaT:
        raise ValueError("start and end must not be NaT")

    if freq is None:
        if is_start_per:
            freq = start.freq
        elif is_end_per:
            freq = end.freq
        else:  # pragma: no cover
            raise ValueError("Could not infer freq from start/end")
        mult = freq.n

    if periods is not None:
        periods = periods * mult
        if start is None:
            data = np.arange(
                end.ordinal - periods + mult, end.ordinal + 1, mult, dtype=np.int64
            )

View on GitHub (pinned to 3b7651241d)