pandas-dev/pandas · error · TypeError

Cannot round dtype {self.dtype} as it is non-numeric

Error message

Cannot round dtype {self.dtype} as it is non-numeric

What it means

ExtensionArray.round (base.py:2945) rejects dtypes that are neither boolean (returned as-is) nor numeric; it raises TypeError. Rounding only makes sense for numeric data, so non-numeric EAs (string, object, datetime) are refused.

Source

Thrown at pandas/core/arrays/base.py:2945

        Series.round : Round values of a Series.

        Notes
        -----
        This is a non-performant default implementation.  Subclasses are
        encouraged to override it to avoid the elementwise loop.

        Examples
        --------
        >>> arr = pd.array([1.234, 5.678, pd.NA], dtype="Float64")
        >>> arr.round(1)
        <FloatingArray>
        [1.2, 5.7, <NA>]
        Length: 3, dtype: Float64
        """
        if self.dtype._is_boolean:
            return self.copy()
        if not self.dtype._is_numeric:
            raise TypeError(f"Cannot round dtype {self.dtype} as it is non-numeric")
        # Python's builtin round on complex emits DeprecationWarning (and
        # raises TypeError in a future Python release); use np.round there.
        round_fn = np.round if self.dtype.kind == "c" else round
        rounded = [
            round_fn(item, decimals) if not item_isna else item
            for item, item_isna in zip(self, self.isna(), strict=True)
        ]
        return type(self)._from_sequence(rounded, dtype=self.dtype)

    def __array_ufunc__(self, ufunc: np.ufunc, method: str, *inputs, **kwargs):
        if any(
            isinstance(other, (ABCSeries, ABCIndex, ABCDataFrame)) for other in inputs
        ):
            return NotImplemented

        result = arraylike.maybe_dispatch_ufunc_to_dunder_op(
            self, ufunc, method, *inputs, **kwargs
        )

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Apply round only to numeric columns: df.select_dtypes(include='number').round().
  2. Convert the column to numeric first: s.astype('Float64').round().
  3. If your custom EA is numeric, ensure its dtype._is_numeric returns True.
  4. Drop or exclude non-numeric columns from the round() call.

Example fix

# before
df.round()  # raises if df has a 'string' column

# after
df_num = df.select_dtypes(include="number")
df[df_num.columns] = df_num.round()
Defensive patterns

Strategy: validation

Validate before calling

def safe_round(s, decimals=0):
    import pandas as pd
    if not pd.api.types.is_numeric_dtype(s):
        return s
    return s.round(decimals)

Type guard

def is_roundable(dtype) -> bool:
    import pandas as pd
    return pd.api.types.is_numeric_dtype(dtype) or pd.api.types.is_bool_dtype(dtype)

Try / catch

try:
    df.round()
except TypeError as e:
    if "non-numeric" in str(e):
        num = df.select_dtypes("number")
        df[num.columns] = num.round()
    else:
        raise

Prevention

When it happens

Trigger: Calling s.round() or df.round() on a Series/column whose EA dtype._is_numeric is False and _is_boolean is False (e.g. string, categorical-of-strings, some custom EA).

Common situations: Running df.round() on a mixed DataFrame that includes string or datetime columns; calling round on a custom EA that did not mark itself numeric; data ingestion that left numeric-looking data as strings.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/3422698b39db0d85. Report an issue: GitHub.