pandas-dev/pandas · error · TypeError

__invert__ is not supported for string dtypes

Error message

__invert__ is not supported for string dtypes

What it means

Raised by ArrowExtensionArray.__invert__ (the ~ operator) when the underlying pyarrow type is a string or large_string. Bitwise NOT is meaningless on strings, so pandas raises TypeError proactively rather than letting pyarrow raise ArrowNotImplementedError. Integer types use bit_wise_not; other types fall through to pc.invert.

Solutions

  1. If you intended a boolean negation, build the boolean mask first: ~s.eq(value) or ~s.isna().
  2. Cast to boolean explicitly before inverting: ~s.astype('boolean[pyarrow]').
  3. Avoid the ~ operator on string arrays; use s != value style comparisons.
  4. Check dtype.kind == 'b' before applying ~.

Example fix

# before
s = pd.Series(['a', 'b'], dtype="string[pyarrow]")
~s  # raises TypeError

# after
~s.eq('a')  # boolean mask, safe to invert
Defensive patterns

Strategy: type-guard

Validate before calling

import pyarrow as pa

def safe_invert(arr):
    if pa.types.is_string(arr._pa_array.type) or pa.types.is_large_string(arr._pa_array.type):
        raise TypeError('cannot invert string array; build a boolean mask first')
    return ~arr

Type guard

import pyarrow as pa

def supports_invert(arr) -> bool:
    t = arr._pa_array.type
    return not (pa.types.is_string(t) or pa.types.is_large_string(t))

Try / catch

try:
    result = ~arr
except TypeError as e:
    if 'string dtypes' in str(e):
        result = ~arr.astype('boolean[pyarrow]')
    else:
        raise

Prevention

When it happens

Trigger: ~arr where arr is an ArrowExtensionArray of dtype string[pyarrow] or large_string[pyarrow]; applying the invert operator to a Series/Index backed by pyarrow strings; chained operations like ~s.isin(values) where s is already boolean-string.

Common situations: Inverting a boolean mask but the Series dtype drifted to string[pyarrow]; pyarrow string inference (PD_IO_* infer_string) turning object columns into strings; migrating from object dtype where ~ on object sometimes 'worked' by accident.

Related errors


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

Appendix: source

Thrown at pandas/core/arrays/arrow/array.py:1065

            # TODO: By using `zero_copy_only` it may be possible to implement this
            raise ValueError(
                "Unable to avoid copy while creating an array as requested."
            )
        elif copy is None:
            # `to_numpy(copy=False)` has the meaning of NumPy `copy=None`.
            copy = False

        return self.to_numpy(dtype=dtype, copy=copy)

    def __invert__(self) -> Self:
        # This is a bit wise op for integer types
        if pa.types.is_integer(self._pa_array.type):
            return self._from_pyarrow_array(pc.bit_wise_not(self._pa_array))
        elif pa.types.is_string(self._pa_array.type) or pa.types.is_large_string(
            self._pa_array.type
        ):
            # Raise TypeError instead of pa.ArrowNotImplementedError
            raise TypeError("__invert__ is not supported for string dtypes")
        else:
            return self._from_pyarrow_array(pc.invert(self._pa_array))

    def __neg__(self) -> Self:
        try:
            return self._from_pyarrow_array(pc.negate_checked(self._pa_array))
        except pa.ArrowNotImplementedError as err:
            raise TypeError(
                f"unary '-' not supported for dtype '{self.dtype}'"
            ) from err

    def __pos__(self) -> Self:
        return self._from_pyarrow_array(self._pa_array)

    def __abs__(self) -> Self:
        return self._from_pyarrow_array(pc.abs_checked(self._pa_array))

    # GH 42600: __getstate__/__setstate__ not necessary once

View on GitHub (pinned to 3b7651241d)