pandas-dev/pandas · error · NotImplementedError

is not supported

Error message

{nonexistent=} is not supported

What it means

Raised by ArrowExtensionArray._dt_tz_localize when the `nonexistent` argument is not one of {'raise','shift_backward','shift_forward'}. These three are mapped to pyarrow's assume_timezone 'raise'/'earliest'/'latest' options; any other value (e.g. 'NaT', 'timedelta') has no arrow equivalent and is rejected.

Solutions

  1. Use one of the supported values: 'raise' (default), 'shift_backward', or 'shift_forward'.
  2. If you need 'NaT' behavior, pre-filter or shift the offending timestamps manually before localizing.

Example fix

# before
ser.dt.tz_localize('US/Eastern', nonexistent='NaT')
# after
ser.dt.tz_localize('US/Eastern', nonexistent='shift_forward')
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = {'raise', 'shift_backward', 'shift_forward'}
if nonexistent not in ALLOWED:
    raise ValueError(f"{nonexistent!r} unsupported on arrow tz_localize; use one of {ALLOWED}")
ser.dt.tz_localize(tz, nonexistent=nonexistent)

Type guard

def is_arrow_supported_nonexistent(v) -> bool:
    return v in {'raise', 'shift_backward', 'shift_forward'}

Try / catch

try:
    out = ser.dt.tz_localize(tz, nonexistent=nonexistent)
except NotImplementedError as e:
    if "nonexistent=" in str(e):
        out = ser.dt.tz_localize(tz, nonexistent='shift_forward')
    else:
        raise

Prevention

When it happens

Trigger: Calling `ser.dt.tz_localize('US/Eastern', nonexistent='NaT')` (or 'shift_forward' is OK, but 'timedelta'/'NaT' are not) on a tz-naive timestamp[pyarrow] Series whose times fall in a forward-DST gap.

Common situations: Using nonexistent strategies supported on datetime64[ns] but absent from the arrow assume_timezone mapping.

Related errors


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

Appendix: source

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

    def _dt_tz_localize(
        self,
        tz,
        ambiguous: TimeAmbiguous = "raise",
        nonexistent: TimeNonexistent = "raise",
    ) -> Self:
        if ambiguous != "raise":
            raise NotImplementedError(f"{ambiguous=} is not supported")
        nonexistent_pa = {
            "raise": "raise",
            "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)

View on GitHub (pinned to 3b7651241d)