pandas-dev/pandas · error · TypeError

bad operand type for unary +

Error message

bad operand type for unary +: '{self.dtype}'

What it means

ArrowStringArray.__pos__ raises TypeError because unary + is meaningless for string data. numpy allows + on numeric arrays; pandas overrides __pos__ to refuse rather than silently return the original or coerce.

Solutions

  1. Remove unary + from string column handling.
  2. Guard numeric-only transforms with select_dtypes('number').
  3. If a no-op copy is required, use s.copy() explicitly.

Example fix

// before
+s  # TypeError on string[pyarrow]
// after
s.copy()  # if a copy was intended
Defensive patterns

Strategy: type-guard

Validate before calling

def safe_unary_pos(s):
    if pd.api.types.is_string_dtype(s):
        raise TypeError('unary + not supported for string dtype')
    return +s

Type guard

def unary_pos_safe(series) -> bool:
    return pd.api.types.is_numeric_dtype(series)

Try / catch

try:
    +s
except TypeError as e:
    if 'unary +' in str(e):
        s = s.copy()  # if a no-op copy was intended
    else:
        raise

Prevention

When it happens

Trigger: +s where s is a string[pyarrow] Series; np.positive(s) on a string column; applying operator.pos to the array.

Common situations: Generic numerical transforms that apply unary + to every column; using +x as a no-op copy across mixed-dtype frames.

Related errors


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

Appendix: source

Thrown at pandas/core/arrays/string_arrow.py:676

    def _cmp_method(self, other, op):
        if (
            isinstance(other, (BaseStringArray, ArrowExtensionArray))
            and self.dtype.na_value is not libmissing.NA
            and other.dtype.na_value is libmissing.NA
        ):
            # NA has priority of NaN semantics
            return NotImplemented

        result = super()._cmp_method(other, op)
        if self.dtype.na_value is np.nan:
            if op == operator.ne:
                return result.to_numpy(np.bool_, na_value=True)
            else:
                return result.to_numpy(np.bool_, na_value=False)
        return result

    def __pos__(self) -> Self:
        raise TypeError(f"bad operand type for unary +: '{self.dtype}'")

View on GitHub (pinned to 3b7651241d)