pandas-dev/pandas · error · ValueError

Could not infer freq from start/end

Error message

Could not infer freq from start/end

What it means

Raised (with pragma: no cover, so it is a defensive guard) when freq is None and neither start nor end is a Period object, so the frequency cannot be inferred. _get_ordinal_range needs at least one Period endpoint or an explicit freq.

Solutions

  1. Always pass an explicit freq= to period_range unless one endpoint is already a Period.
  2. Convert one endpoint to pd.Period(value, freq) so the freq is carried.
  3. Use date_range instead if you do not actually need period semantics.

Example fix

# before
pd.period_range('2020-01-01', '2020-01-10')
# after
pd.period_range('2020-01-01', '2020-01-10', freq='D')
Defensive patterns

Strategy: validation

Validate before calling

from pandas import Period

def can_infer_freq(start, end, freq) -> bool:
    return freq is not None or isinstance(start, Period) or isinstance(end, Period)

Type guard

def has_period_endpoint_or_freq(start, end, freq) -> bool:
    return freq is not None or isinstance(start, pd.Period) or isinstance(end, pd.Period)

Try / catch

try:
    pr = pd.period_range(start, end, freq=freq)
except ValueError as e:
    if 'Could not infer freq' in str(e):
        pr = pd.period_range(start, end, freq='D')  # explicit default
    else:
        raise

Prevention

When it happens

Trigger: Calling period_range with start/end as plain strings or Timestamps and no freq= argument; mixing string endpoints with periods= but omitting freq.

Common situations: Assuming period_range will infer a freq from strings the way date_range infers from datetime data; refactor that dropped the freq kwarg; copy-paste from date_range usage.

Related errors


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

Appendix: source

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

        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
            )
        else:
            data = np.arange(
                start.ordinal, start.ordinal + periods, mult, dtype=np.int64
            )
    else:
        data = np.arange(start.ordinal, end.ordinal + 1, mult, dtype=np.int64)

    return data, freq

View on GitHub (pinned to 3b7651241d)