pandas-dev/pandas · error · TypeError

cannot add the type to a

Error message

cannot add the type {type(other).__name__} to a {type(self).__name__}

What it means

Raised by TimedeltaArray._add_offset when an attempt is made to add a DateOffset-like object (other than Tick or Day, which are handled earlier) to a timedelta64 array. Calendar/anchored offsets (e.g. MonthEnd, YearBegin, BusinessDay) are semantically meaningless when added to a pure duration, so pandas refuses rather than produce a nonsensical result. The assert guards the already-handled Tick/Day case; everything else falls through to the TypeError.

Solutions

  1. Operate on datetime64 data instead: cast the timedelta to a Timestamp base first, or apply the offset to a DatetimeIndex/Series.
  2. If the intent is to scale a duration, use an integer/float multiplier rather than a DateOffset.
  3. For Tick/Day offsets specifically use those types directly, since they are handled by a separate path and will not hit this error.

Example fix

# before
s = pd.Series(pd.to_timedelta([1, 2, 3], unit='D'))
s + pd.offsets.MonthEnd(1)  # TypeError

# after (apply offset to datetime data)
ts = pd.Timestamp('2020-01-01')
ts + pd.offsets.MonthEnd(1)
Defensive patterns

Strategy: type-guard

Validate before calling

from pandas.tseries.offsets import DateOffset, Tick, Day

def is_offset_addable_to_td(other) -> bool:
    # only Tick/Day are addable to timedelta; anything else is rejected
    return isinstance(other, (Tick, Day)) or not isinstance(other, DateOffset)

Type guard

from pandas.tseries.offsets import DateOffset, Tick, Day

def can_add_to_timedelta(other) -> bool:
    """True if `other` is a valid addend for timedelta64 data."""
    if isinstance(other, DateOffset):
        return isinstance(other, (Tick, Day))
    return True

Try / catch

try:
    result = td_array + other
except TypeError as e:
    if 'cannot add the type' in str(e):
        # offset is incompatible with timedelta; route to datetime arithmetic
        raise
    raise

Prevention

When it happens

Trigger: Adding a non-Tick DateOffset to a Series/Index of dtype timedelta64[ns], e.g. `pd.Series(pd.to_timedelta(range(3), unit='D')) + pd.offsets.MonthEnd(1)`, or dispatching `TimedeltaArray.__add__` with an offset operand through the offsets arithmetic path.

Common situations: Mixing offset-based date arithmetic (intended for datetime64) with timedelta64 data; code ported from a Timestamp/TimestampIndex context that reused the same offset operand against durations.

Related errors


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

Appendix: source

Thrown at pandas/core/arrays/timedeltas.py:473

        return get_format_timedelta64(self, box=True)

    def _format_native_types(
        self, *, na_rep: str | float = "NaT", date_format=None, **kwargs
    ) -> npt.NDArray[np.object_]:
        from pandas.io.formats.format import get_format_timedelta64

        # Relies on TimeDelta._repr_base
        formatter = get_format_timedelta64(self, na_rep)
        # equiv: np.array([formatter(x) for x in self._ndarray])
        #  but independent of dimension
        return np.frompyfunc(formatter, 1, 1)(self._ndarray)

    # ----------------------------------------------------------------
    # Arithmetic Methods

    def _add_offset(self, other):
        assert not isinstance(other, (Tick, Day))
        raise TypeError(
            f"cannot add the type {type(other).__name__} to a {type(self).__name__}"
        )

    def _mul_float_overflowsafe(
        self, other: float | np.floating | npt.NDArray[np.floating]
    ) -> Self:
        # GH#43178: detect float products that would silently saturate to
        #  int64.max on the int64 cast below
        i8 = self.asi8
        self_mask = i8 == iNaT
        if self_mask.any():
            # zero out NaT positions so they don't trigger the bounds check
            i8 = np.where(self_mask, 0, i8)
        f_result = i8 * other
        nan_mask = np.isnan(f_result)
        non_nan = f_result[~nan_mask]
        # Compare against 2**63, not i8max: i8max (2**63 - 1) rounds up to
        #  2**63 in float64, so a product landing exactly on 2**63 would slip

View on GitHub (pinned to 3b7651241d)