pandas-dev/pandas · error · TypeError
Cannot convert tz-naive timestamps, use tz_localize to…
Error message
Cannot convert tz-naive timestamps, use tz_localize to localize
What it means
Raised (as TypeError) by ArrowExtensionArray._dt_tz_convert when the array's pyarrow timestamp type has no timezone (tz is None). Converting timezones is only meaningful for tz-aware data; for tz-naive data you must first assign (localize to) a timezone. The message points the user at tz_localize.
Solutions
- Localize first: `ser.dt.tz_localize('UTC').dt.tz_convert('US/Eastern')`.
- Inspect `ser.dtype.pyarrow_dtype.tz` — if None, you need tz_localize, not tz_convert.
Example fix
# before
ser.dt.tz_convert('US/Eastern') # ser is tz-naive
# after
ser.dt.tz_localize('UTC').dt.tz_convert('US/Eastern') Defensive patterns
Strategy: validation
Validate before calling
if ser.dtype.pyarrow_dtype.tz is None:
raise TypeError("Series is tz-naive; call tz_localize before tz_convert")
ser.dt.tz_convert(tz) Type guard
def is_arrow_tz_aware(ser) -> bool:
t = getattr(ser.dtype, "pyarrow_dtype", None)
return t is not None and getattr(t, "tz", None) is not None Try / catch
try:
out = ser.dt.tz_convert(tz)
except TypeError as e:
if "tz-naive" in str(e):
out = ser.dt.tz_localize('UTC').dt.tz_convert(tz)
else:
raise Prevention
- Check pyarrow_dtype.tz before tz_convert
- Localize naive timestamps before converting
When it happens
Trigger: Calling `ser.dt.tz_convert('UTC')` on a Series whose dtype is `timestamp[ns][pyarrow]` with no timezone attached.
Common situations: Forgetting that tz_convert is the second step (after tz_localize); reading tz-naive arrow data and immediately trying to convert to UTC.
Related errors
- ambiguous is not supported.
- is not supported
- nonexistent is not supported.
- is not supported
- as_unit not implemented for
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/43021e75a4f0f5b4.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/arrow/array.py:4307
"shift_backward": "earliest",
"shift_forward": "latest",
}.get(
nonexistent, # type: ignore[arg-type]
None,
)
if nonexistent_pa is None:
raise NotImplementedError(f"{nonexistent=} is not supported")
if tz is None:
result = pc.local_timestamp(self._pa_array)
else:
result = pc.assume_timezone(
self._pa_array, str(tz), ambiguous=ambiguous, nonexistent=nonexistent_pa
)
return self._from_pyarrow_array(result)
def _dt_tz_convert(self, tz) -> Self:
if self.dtype.pyarrow_dtype.tz is None:
raise TypeError(
"Cannot convert tz-naive timestamps, use tz_localize to localize"
)
current_unit = self.dtype.pyarrow_dtype.unit
result = self._pa_array.cast(pa.timestamp(current_unit, tz))
return self._from_pyarrow_array(result)
def transpose_homogeneous_pyarrow(
arrays: Sequence[ArrowExtensionArray],
) -> list[ArrowExtensionArray]:
"""Transpose arrow extension arrays in a list, but faster.
Input should be a list of arrays of equal length and all have the same
dtype. The caller is responsible for ensuring validity of input data.
"""
arrays = list(arrays)
nrows, ncols = len(arrays[0]), len(arrays)
indices = np.arange(nrows * ncols).reshape(ncols, nrows).T.reshape(-1)View on GitHub (pinned to 3b7651241d)