pandas-dev/pandas · error · ValueError
'unit' must be one of 's', 'ms', 'us', 'ns'
Error message
'unit' must be one of 's', 'ms', 'us', 'ns'
What it means
Raised by DatetimeArray._generate_range when the unit argument is not None and not in ['s','ms','us','ns']. date_range only supports those four resolutions for its backing datetime64 dtype; any other unit string (including numpy-style like 'm','h') is rejected up front so the range is never built at the wrong precision.
Solutions
- Use one of 's','ms','us','ns'; for minute/hour precision choose 's' (coarsest supported).
- Normalize a user unit string at the config boundary: UNIT_MAP = {'minute':'s','hour':'s','second':'s'}.
- If sub-nanosecond is required, keep values as int64 counts; pandas cannot represent them as datetime64.
Example fix
// before
pd.date_range('2020-01-01', periods=3, unit='m') # ValueError: 'unit' must be one of ...
// after
pd.date_range('2020-01-01', periods=3, unit='s') Defensive patterns
Strategy: validation
Validate before calling
SUPPORTED_UNITS = {"s","ms","us","ns"}
UNIT_MAP = {"minute":"s","hour":"s","second":"s","millisecond":"ms","microsecond":"us","nanosecond":"ns"}
def safe_unit(u):
u = UNIT_MAP.get(str(u).lower(), u)
if u not in SUPPORTED_UNITS:
raise ValueError(f"unit must be one of {SUPPORTED_UNITS}")
return u Type guard
def is_supported_date_range_unit(unit: str) -> bool:
return unit in {"s","ms","us","ns"} Try / catch
try:
rng = pd.date_range(start, periods=5, freq="D", unit=unit)
except ValueError as e:
if "'unit' must be one of" in str(e):
rng = pd.date_range(start, periods=5, freq="D", unit="s")
else:
raise Prevention
- Expose unit through an enum/allowlist in public APIs.
- Normalize free-text unit strings at the config boundary.
- Document the four supported units near date_range usage.
When it happens
Trigger: pd.date_range(..., unit='m'); pd.date_range(..., unit='ps'); pd.date_range(..., unit='hours'); passing a config-driven unit string without normalization.
Common situations: Mapping from a different unit vocabulary (numpy timedelta codes, ISO durations); user-configurable unit fields; copy-paste from as_unit calls that also restrict to the same four.
Related errors
- Supported units are 's', 'ms', 'us', 'ns'
- Cannot convert from to . Supported resolutions are 's'…
- does not have a resolution.
- freq= is incompatible with unit= . Use a lower freq or a…
- Must provide freq argument if no data is supplied
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/eb025f3518c3f748.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/datetimes.py:426
if com.count_not_none(start, end, periods, freq) != 3:
raise ValueError(
"Of the four parameters: start, end, periods, "
"and freq, exactly three must be specified"
)
freq = to_offset(freq)
if start is not None:
start = Timestamp(start)
if end is not None:
end = Timestamp(end)
if start is NaT or end is NaT:
raise ValueError("Neither `start` nor `end` can be NaT")
if unit is not None:
if unit not in ["s", "ms", "us", "ns"]:
raise ValueError("'unit' must be one of 's', 'ms', 'us', 'ns'")
else:
unit = "ns"
if start is not None:
start = start.as_unit(unit, round_ok=False)
if end is not None:
end = end.as_unit(unit, round_ok=False)
left_inclusive, right_inclusive = validate_inclusive(inclusive)
start, end = _maybe_normalize_endpoints(start, end, normalize)
tz = _infer_tz_from_endpoints(start, end, tz)
if tz is not None:
# Localize the start and end arguments
start = _maybe_localize_point(start, freq, tz, ambiguous, nonexistent)
end = _maybe_localize_point(end, freq, tz, ambiguous, nonexistent)
if freq is not None:View on GitHub (pinned to 3b7651241d)