pandas-dev/pandas · error · ValueError

Must specify a valid frequency: {freq}

Error message

Must specify a valid frequency: {freq}

What it means

Raised by ArrowExtensionArray._round_temporally when pandas.tseries.frequencies.to_offset(freq) returns None, i.e. the `freq` string cannot be parsed as a valid pandas offset alias. The pyarrow rounding path requires a recognized frequency to map to a pyarrow temporal unit. Reached through dt.ceil/floor/round on a pyarrow-backed timestamp Series.

Source

Thrown at pandas/core/arrays/arrow/array.py:4177

    def _dt_strftime(self, format: str) -> Self:
        result = pc.strftime(self._pa_array, format=format)
        return self._from_pyarrow_array(result)

    def _round_temporally(
        self,
        method: Literal["ceil", "floor", "round"],
        freq,
        ambiguous: TimeAmbiguous = "raise",
        nonexistent: TimeNonexistent = "raise",
    ) -> Self:
        if ambiguous != "raise":
            raise NotImplementedError("ambiguous is not supported.")
        if nonexistent != "raise":
            raise NotImplementedError("nonexistent is not supported.")
        offset = to_offset(freq)
        if offset is None:
            raise ValueError(f"Must specify a valid frequency: {freq}")
        pa_supported_unit = {
            "Y": "year",
            "YS": "year",
            "Q": "quarter",
            "QS": "quarter",
            "M": "month",
            "MS": "month",
            "W": "week",
            "D": "day",
            "h": "hour",
            "min": "minute",
            "s": "second",
            "ms": "millisecond",
            "us": "microsecond",
            "ns": "nanosecond",
        }
        unit = pa_supported_unit.get(offset._prefix, None)
        if unit is None:

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Use a valid alias: 's','min','h','D','W','M','MS','Q','QS','Y','YS','ms','us','ns' optionally prefixed by a multiple like '30min'.
  2. Validate with `pd.tseries.frequencies.to_offset(freq)` before calling; if it returns None, reject early.
  3. Pass a DateOffset instance that to_offset understands, e.g. `pd.offsets.Hour()`.
  4. Check for trailing/leading whitespace or typos in the string.

Example fix

# before
s.dt.floor("30mins")  # typo -> ValueError

# after
s.dt.floor("30min")
Defensive patterns

Strategy: validation

Validate before calling

from pandas.tseries.frequencies import to_offset

def is_valid_freq(freq) -> bool:
    try:
        return to_offset(freq) is not None
    except (ValueError, TypeError):
        return False

def safe_round(s, freq, method="floor"):
    if not is_valid_freq(freq):
        raise ValueError(f"Invalid frequency: {freq!r}")
    return s.dt.__getattribute__(method)(freq)

Type guard

from pandas.tseries.frequencies import to_offset

def is_valid_freq(freq) -> bool:
    try:
        return to_offset(freq) is not None
    except Exception:
        return False

Try / catch

try:
    out = s.dt.floor(freq)
except ValueError as e:
    if "valid frequency" in str(e):
        raise ValueError(f"Fix freq alias: {freq!r}. Valid: s,min,h,D,W,M,MS,Q,QS,Y,YS,ms,us,ns") from e
    raise

Prevention

When it happens

Trigger: Calling `s.dt.floor("xyz")`, `s.dt.round("")`, `s.dt.ceil(None)` (where None is passed positionally), or any unparseable/non-string freq on timestamp[pyarrow]. Also when freq is a malformed alias like '1X'.

Common situations: Typos in freq strings; dynamically building freq from user input; passing a numeric instead of a string; confusing the freq alias with a DateOffset object that to_offset cannot parse.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/3193d7aa6d98fdf4. Report an issue: GitHub.