pandas-dev/pandas · error · ValueError

'value' should be a Timestamp.

Error message

'value' should be a Timestamp.

What it means

Raised by DatetimeArray._unbox_scalar when the value passed to setitem/search/etc. is neither an instance of the array's _scalar_type (Timestamp) nor pd.NaT. Internally pandas unboxes scalars to raw datetime64 to compare/store them; a non-Timestamp object (e.g. a python datetime, a string, an int) cannot be unboxed without ambiguity, so it is rejected at this low level.

Solutions

  1. Wrap the value: pd.Timestamp(value) before passing.
  2. Use the public setitem / .get_loc / .get_indexer APIs which coerce for you.
  3. If you need NaT semantics, pass pd.NaT explicitly rather than None.

Example fix

// before
val = datetime.datetime(2020, 1, 1)
idx._unbox_scalar(val)  # ValueError: 'value' should be a Timestamp.

// after
val = pd.Timestamp(datetime.datetime(2020, 1, 1))
idx._unbox_scalar(val)
Defensive patterns

Strategy: type-guard

Validate before calling

def unbox_for_dt(idx, value):
    if value is not pd.NaT and not isinstance(value, pd.Timestamp):
        value = pd.Timestamp(value)
    return idx._unbox_scalar(value)

Type guard

def is_timestamp_or_nat(value) -> bool:
    return value is pd.NaT or isinstance(value, pd.Timestamp)

Try / catch

try:
    raw = idx._unbox_scalar(value)
except ValueError as e:
    if "should be a Timestamp" in str(e):
        raw = idx._unbox_scalar(pd.Timestamp(value))
    else:
        raise

Prevention

When it happens

Trigger: Indexing/setting a DatetimeArray/DatetimeIndex with a python datetime.datetime, a str, or an int directly through the internal _unbox_scalar path (e.g. idx._unbox_scalar(value)); less commonly hit via public setitem when the value bypasses normal coercion.

Common situations: Subclassing/extending DatetimeArray and feeding raw python datetime objects; calling internal methods directly; mixed-type assignment that skips the public coercion layer.

Related errors


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

Appendix: source

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

                if len(i8values)
                else 0
            )
            if not left_inclusive or not right_inclusive:
                if not left_inclusive and len(i8values) and i8values[0] == start_i8:
                    i8values = i8values[1:]
                if not right_inclusive and len(i8values) and i8values[-1] == end_i8:
                    i8values = i8values[:-1]

        dt64_values = i8values.view(f"datetime64[{unit}]")
        dtype = tz_to_dtype(tz, unit=unit)
        return cls._simple_new(dt64_values, dtype=dtype)

    # -----------------------------------------------------------------
    # DatetimeLike Interface

    def _unbox_scalar(self, value) -> np.datetime64:
        if not isinstance(value, self._scalar_type) and value is not NaT:
            raise ValueError("'value' should be a Timestamp.")
        self._check_compatible_with(value)
        if value is NaT:
            return np.datetime64(value._value, self.unit)
        else:
            return value.as_unit(self.unit, round_ok=False).asm8

    def _scalar_from_string(self, value) -> Timestamp | NaTType:
        return Timestamp(value, tz=self.tz)

    def _check_compatible_with(self, other) -> None:
        if other is NaT:
            return
        self._assert_tzawareness_compat(other)

    # -----------------------------------------------------------------
    # Descriptive Properties

    def _box_func(self, x: np.datetime64) -> Timestamp | NaTType:

View on GitHub (pinned to 3b7651241d)