pola-rs/polars · error · TypeError

cannot do arithmetic with Series of dtype

Error message

cannot do arithmetic with Series of dtype: {self.dtype!r} and argument of type: {type(other).__name__!r}

What it means

_arithmetic dispatches +, -, *, /, % to a dtype-specific FFI function. When no implementation exists for the combination of the Series' dtype and the operand's Python type, it raises TypeError describing both sides. Polars does not silently coerce arbitrary type pairs for arithmetic; the user must cast explicitly.

Solutions

  1. Cast the operand or Series to a compatible dtype first, e.g. s.cast(pl.Int64) + 1 for numeric strings, or s.str.to_datetime() for date-like strings.
  2. For string concatenation, use explicit string APIs (s.str.concat / + between two Utf8 Series) — never Series + int.
  3. Rewrite as an expression for more flexible coercion: s.to_frame().select(pl.col(name) + other), which also gives clearer dtype errors.
  4. If mixing temporal and numeric types, cast the temporal column to Int64 first (s.cast(pl.Int64) or s.dt.epoch(...)) and re-cast afterwards.

Example fix

// before
s = pl.Series('n', ['1', '2', '3'])  # dtype Utf8
s + 1  # TypeError: cannot do arithmetic with Series of dtype: String and argument of type: 'int'

// after
s.cast(pl.Int64) + 1
Defensive patterns

Strategy: validation

Validate before calling

NUMERIC = (pl.Int8, pl.Int16, pl.Int32, pl.Int64, pl.UInt8, pl.UInt16, pl.UInt32, pl.UInt64, pl.Float32, pl.Float64)
assert s.dtype in NUMERIC or not isinstance(other, (int, float)), \
    f'cast operands to a numeric dtype before arithmetic (got {s.dtype} and {type(other).__name__})'

Type guard

def arithmetic_compatible(dtype: pl.DataType, other) -> bool:
    if isinstance(dtype, (pl.List, pl.Struct, pl.Object)):
        return False
    if dtype == pl.Utf8:
        return isinstance(other, str) or (isinstance(other, pl.Series) and other.dtype == pl.Utf8)
    return isinstance(other, (int, float, pl.Series))

Try / catch

try:
    result = s + other
except TypeError as e:
    if 'cannot do arithmetic with Series of dtype' in str(e):
        result = s.cast(pl.Int64) + other  # or str.to_datetime()/to_numeric() as appropriate
    else:
        raise

Prevention

When it happens

Trigger: Applying +, -, *, / or % between a Series and an operand of an unsupported type, e.g. string_series + 1, int_series + 'abc', or arithmetic on List/Struct/Object-typed Series.

Common situations: Forgetting to parse numeric columns read from CSV (they stay Utf8/String, so 'col' + 1 fails); mixing string concatenation with numeric literals; passing datetimes or lists as operands instead of scalars or matching-dtype Series.

Related errors


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/5c7da5edd88c8f68. Report an issue: GitHub.

Appendix: source

Thrown at py-polars/src/polars/series/series.py:1085

            if isinstance(other, int):
                pyseries = sequence_to_pyseries(self.name, [other])
                _s = self._from_pyseries(pyseries).cast(Decimal(scale=0))._s
            else:
                _s = sequence_to_pyseries(self.name, [other], dtype=Decimal)

            if "rhs" in op_ffi:
                return self._from_pyseries(getattr(_s, op_s)(self._s))
            else:
                return self._from_pyseries(getattr(self._s, op_s)(_s))
        else:
            other = maybe_cast(other, self.dtype)
            f = get_ffi_func(op_ffi, self.dtype, self._s)
        if f is None:
            msg = (
                f"cannot do arithmetic with Series of dtype: {self.dtype!r} and argument"
                f" of type: {type(other).__name__!r}"
            )
            raise TypeError(msg)
        return self._from_pyseries(f(other))

    @overload
    def __add__(self, other: DataFrame) -> DataFrame: ...

    @overload
    def __add__(self, other: Expr) -> Expr: ...

    @overload
    def __add__(self, other: Any) -> Self: ...

    def __add__(self, other: Any) -> Series | DataFrame | Expr:
        if isinstance(other, str):
            other = Series("", [other])
        elif isinstance(other, pl.DataFrame):
            return other + self
        elif isinstance(other, pl.Expr):
            return F.lit(self) + other

View on GitHub (pinned to fe841f959e)