pandas-dev/pandas · error · ValueError

cannot supply both a tz and a timezone-naive dtype (i.e…

Error message

cannot supply both a tz and a timezone-naive dtype (i.e. datetime64[ns])

What it means

Raised by _validate_tz_from_dtype when a tz kwarg is supplied, the dtype is a numpy datetime64 ('M' kind, hence tz-naive), and the tz disagrees with the (None) dtype tz via timezones.tz_compare. The message names the specific case: the user passed both a tz kwarg and a tz-naive datetime64 dtype. Practically unreachable when tz is None, but fires for any non-None tz paired with a plain datetime64[ns] dtype that should have been a DatetimeTZDtype.

Solutions

  1. Use a consistent representation: either drop the dtype and pass tz, or use a tz-aware dtype and drop the tz kwarg.
  2. Prefer `pd.DatetimeIndex(values, tz='UTC')` and let pandas construct the right DatetimeTZDtype.
  3. If the dtype is fixed upstream, strip the tz kwarg and let the dtype win.

Example fix

// before
dti = pd.DatetimeIndex(values, dtype='datetime64[ns]', tz='UTC')

// after
dti = pd.DatetimeIndex(values, tz='UTC')
Defensive patterns

Strategy: validation

Validate before calling

import pandas as pd, numpy as np

def reconcile_np_m_dtype_with_tz(dtype_str, tz):
    if dtype_str and tz is not None:
        try:
            d = pd.api.types.pandas_dtype(dtype_str)
            if isinstance(d, np.dtype) and d.kind == 'M' and getattr(d, 'tz', None) is None:
                return None, tz  # drop dtype, keep tz kwarg
        except TypeError:
            pass
    return dtype_str, tz

Type guard

def no_tz_naive_np_m_with_tz(dtype_str, tz) -> bool:
    import numpy as np, pandas as pd
    if tz is None or not dtype_str:
        return True
    try:
        d = pd.api.types.pandas_dtype(dtype_str)
    except TypeError:
        return True
    return not (isinstance(d, np.dtype) and d.kind == 'M' and getattr(d, 'tz', None) is None)

Try / catch

try:
    dti = pd.DatetimeIndex(values, dtype=dtype_str, tz=tz)
except ValueError as e:
    if 'timezone-naive dtype' in str(e):
        dti = pd.DatetimeIndex(values, tz=tz)
    else:
        raise

Prevention

When it happens

Trigger: Calling `pd.DatetimeIndex(values, dtype='datetime64[ns]', tz='UTC')` — the dtype string is tz-naive but a tz kwarg is also given. Functionally pandas will usually reconcile by adopting the tz kwarg, but in the conflict path (mismatched compare) it raises this.

Common situations: Code that simultaneously passes a fixed tz-naive default dtype and a tz kwarg with different intent. Migration where the dtype was hardcoded tz-naive and a tz kwarg was added later.

Related errors


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

Appendix: source

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

            except TypeError:
                # Things like `datetime64[ns]`, which is OK for the
                # constructors, but also nonsense, which should be validated
                # but not by us. We *do* allow non-existent tz errors to
                # go through
                pass
        dtz = getattr(dtype, "tz", None)
        if dtz is not None:
            if tz is not None and not timezones.tz_compare(tz, dtz):
                raise ValueError("cannot supply both a tz and a dtype with a tz")
            if explicit_tz_none:
                raise ValueError("Cannot pass both a timezone-aware dtype and tz=None")
            tz = dtz

        if tz is not None and lib.is_np_dtype(dtype, "M"):
            # We also need to check for the case where the user passed a
            #  tz-naive dtype (i.e. datetime64[ns])
            if tz is not None and not timezones.tz_compare(tz, dtz):
                raise ValueError(
                    "cannot supply both a tz and a "
                    "timezone-naive dtype (i.e. datetime64[ns])"
                )

    return tz


def _infer_tz_from_endpoints(
    start: Timestamp, end: Timestamp, tz: tzinfo | None
) -> tzinfo | None:
    """
    If a timezone is not explicitly given via `tz`, see if one can
    be inferred from the `start` and `end` endpoints.  If more than one
    of these inputs provides a timezone, require that they all agree.

    Parameters
    ----------
    start : Timestamp

View on GitHub (pinned to 3b7651241d)