pandas-dev/pandas · error · ValueError

to_concat must have the same dtype

Error message

to_concat must have the same dtype

What it means

`ValueError('to_concat must have the same dtype', dtypes)` from `NDArrayBackedExtensionArray._concat_same_type`. Despite the method's name, it verifies via `lib.dtypes_all_equal` that every array's dtype string matches, and raises with the set of distinct dtype strings if not. This catches mismatches such as different timezones on DatetimeArray, different units on TimedeltaArray, or different Arrow element types.

Solutions

  1. Unify dtypes before concatenating: `s1 = s1.astype(s2.dtype)` then `pd.concat([s1, s2])`.
  2. For tz-aware datetimes, normalize timezone: `s1 = s1.dt.tz_convert(s2.dt.tz)`.
  3. For Arrow arrays, unify pyarrow types via `s.astype(pd.ArrowDtype(pa_target_type))` before concat.
  4. If the mismatch is intentional, let pandas route through the generic `concat` path (do not call `_concat_same_type` directly).

Example fix

// before
pd.concat([s_us, s_s])   # timedelta64[us] vs [s] -> ValueError

// after
pd.concat([s_us.astype('timedelta64[s]'), s_s])
Defensive patterns

Strategy: validation

Validate before calling

dtypes = {str(a.dtype) for a in to_concat}
if len(dtypes) > 1:
    target = next(iter(to_concat)).dtype
    to_concat = [a.astype(target) for a in to_concat]
result = type(to_concat[0])._concat_same_type(to_concat)

Type guard

def same_dtype(arrays) -> bool:
    first = str(arrays[0].dtype)
    return all(str(a.dtype) == first for a in arrays)

Try / catch

try:
    out = cls._concat_same_type(parts)
except ValueError as e:
    if 'to_concat must have the same dtype' in str(e):
        target = parts[0].dtype
        out = cls._concat_same_type([p.astype(target) for p in parts])
    else:
        raise

Prevention

When it happens

Trigger: `pd.concat([Series(dtype=tz1), Series(dtype=tz2)])` where the dtypes are not string-equal; concatenating TimedeltaArrays of different units; concatenating ArrowExtensionArrays whose pyarrow types differ but share the EA class; calling `cls._concat_same_type([...])` directly with mixed dtypes.

Common situations: Concatenating tz-aware datetime Series with different timezones; mixing `timedelta64[ns]` with `timedelta64[s]` (pandas 2.x unit support); concatenating Arrow-backed Series with subtly different pyarrow schemas (e.g. `int32` vs `int64`).

Related errors


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

Appendix: source

Thrown at pandas/core/arrays/_mixins.py:268

    def _concat_same_type(
        cls,
        to_concat: Sequence[Self],
        axis: AxisInt = 0,
    ) -> Self:
        """
        Concatenate multiple arrays of this dtype.

        Parameters
        ----------
        to_concat : sequence of this type

        Returns
        -------
        ExtensionArray
        """
        if not lib.dtypes_all_equal([x.dtype for x in to_concat]):
            dtypes = {str(x.dtype) for x in to_concat}
            raise ValueError("to_concat must have the same dtype", dtypes)

        return super()._concat_same_type(to_concat, axis=axis)

    def searchsorted(
        self,
        value: NumpyValueArrayLike | ExtensionArray,
        side: Literal["left", "right"] = "left",
        sorter: NumpySorter | None = None,
    ) -> npt.NDArray[np.intp] | np.intp:
        """
        Find indices where elements should be inserted to maintain order.

        Find the indices into a sorted array `self` (a) such that, if the
        corresponding elements in `value` were inserted before the indices,
        the order of `self` would be preserved.

        Assuming that `self` is sorted:

View on GitHub (pinned to 3b7651241d)