pandas-dev/pandas · error · ValueError

Passed data is timezone-aware, incompatible with 'tz=None'.

Error message

Passed data is timezone-aware, incompatible with 'tz=None'. Use obj.tz_localize(None) instead.

What it means

Raised during DatetimeArray construction when tz is explicitly None (explicit_tz_none) but the values are detected as timezone-aware. Silently stripping a tz in this case would be a destructive implicit conversion, so pandas refuses and points at the intentional APIs (tz_localize/tz_convert).

Source

Thrown at pandas/core/arrays/datetimes.py:371

            unit = dtl.dtype_to_unit(dtype)

        data, copy = dtl.ensure_arraylike_for_datetimelike(
            data, copy, cls_name="DatetimeArray"
        )

        subarr, tz = _sequence_to_dt64(
            data,
            copy=copy,
            tz=tz,
            dayfirst=dayfirst,
            yearfirst=yearfirst,
            ambiguous=ambiguous,
            out_unit=unit,
        )
        # We have to call this again after possibly inferring a tz above
        _validate_tz_from_dtype(dtype, tz, explicit_tz_none)
        if tz is not None and explicit_tz_none:
            raise ValueError(
                "Passed data is timezone-aware, incompatible with 'tz=None'. "
                "Use obj.tz_localize(None) instead."
            )

        data_unit = np.datetime_data(subarr.dtype)[0]
        data_unit = cast("TimeUnit", data_unit)
        data_dtype = tz_to_dtype(tz, data_unit)
        result = cls._simple_new(subarr, dtype=data_dtype)
        if unit is not None and unit != result.unit:
            # If unit was specified in user-passed dtype, cast to it here
            # error: Argument 1 to "as_unit" of "TimelikeOps" has
            # incompatible type "str"; expected "Literal['s', 'ms', 'us', 'ns']"
            # [arg-type]
            result = result.as_unit(unit)  # type: ignore[arg-type]

        return result

    @classmethod

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Drop the tz intentionally via obj.tz_localize(None).
  2. If you want naive UTC, first tz_convert('UTC') then tz_localize(None).
  3. Stop passing tz=None explicitly when feeding tz-aware data; let the inferred tz stick or pass the matching tz.

Example fix

# before
pd.DatetimeIndex(tz_aware_series, tz=None)

# after
pd.DatetimeIndex(tz_aware_series).tz_localize(None)
# or to anchor to UTC first:
tz_aware_series.dt.tz_convert('UTC').dt.tz_localize(None)
Defensive patterns

Strategy: type-guard

Validate before calling

if getattr(series.dtype, 'tz', None) is not None and tz is None:
    raise ValueError('data is tz-aware; call .tz_localize(None) instead of tz=None')

Type guard

def is_tz_aware(s) -> bool:
    d = getattr(s, 'dtype', None)
    return isinstance(d, pd.DatetimeTZDtype) or getattr(d, 'tz', None) is not None

Try / catch

try:
    pd.DatetimeIndex(data, tz=tz)
except ValueError as e:
    if 'incompatible with' in str(e) and 'tz=None' in str(e):
        pd.DatetimeIndex(data).tz_localize(None)
    else: raise

Prevention

When it happens

Trigger: pd.DatetimeIndex(tz_aware_series, tz=None), pd.to_datetime(tz_aware_series).tz_localize(None) mis-wired, or constructing a Series/Index by passing tz-aware Timestamps while passing tz=None explicitly. Also pd.DatetimeIndex(..., tz=None) with tz-aware inputs.

Common situations: Trying to 'remove' a timezone by passing tz=None to the constructor instead of calling tz_localize(None). Refactoring that swapped tz_localize for a constructor kwarg. Dashboard code wanting 'naive UTC' display.

Related errors


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