pandas-dev/pandas · error · ValueError
Must specify a valid frequency
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, meaning the value cannot be parsed as a valid frequency/offset alias. The check happens before the supported-prefix lookup, so even valid-but-unsupported offsets never reach the later 'not supported' message.
Solutions
- Use a valid frequency alias such as 'h', 'D', 'min', 's', 'W', 'M', 'Q', or 'Y' (optionally with a multiplier like '2h').
- If constructing freq programmatically, validate it with `pd.tseries.frequencies.to_offset(freq)` first and handle None.
Example fix
# before
ser.dt.floor('xyz')
# after
ser.dt.floor('h') Defensive patterns
Strategy: validation
Validate before calling
from pandas.tseries.frequencies import to_offset
if to_offset(freq) is None:
raise ValueError(f"invalid frequency: {freq!r}")
ser.dt.floor(freq) Type guard
def is_valid_freq(freq) -> bool:
from pandas.tseries.frequencies import to_offset
return to_offset(freq) is not None Try / catch
try:
out = ser.dt.floor(freq)
except ValueError as e:
if "valid frequency" in str(e):
out = ser.dt.floor('h') # use a safe default
else:
raise Prevention
- Validate user-supplied freq with to_offset before rounding
- Whitelist allowed frequency aliases at the input boundary
When it happens
Trigger: Calling `.dt.floor/.dt.ceil/.dt.round` on a timestamp[pyarrow] Series with a value that is not a frequency string or DateOffset, e.g. `ser.dt.floor('xyz')`, `ser.dt.floor(5)`, or `ser.dt.floor('')`.
Common situations: Typos in frequency aliases; passing a bare integer thinking it means 'N seconds'; building the freq dynamically from unvalidated input.
Related errors
- is not supported
- ambiguous is not supported.
- is not supported
- as_unit not implemented for
- Cannot convert tz-naive timestamps, use tz_localize to…
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/3193d7aa6d98fdf4.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/arrow/array.py:4205
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 3b7651241d)