pandas-dev/pandas · error · TypeError

Cannot compare types {type_names[0]!r} and {type_names[1]!r}

Error message

Cannot compare types {type_names[0]!r} and {type_names[1]!r}

What it means

TypeError raised in _check_comparison_types during replace: when an element-wise comparison between the array and a value reduces to a scalar bool (not an element-wise array), pandas infers the two types are not comparable and reports the ndarray dtype and the scalar type. This prevents silently returning an all-False mask.

Source

Thrown at pandas/core/array_algos/replace.py:81

    -------
    mask : array-like of bool
    """
    if isna(b):
        return ~mask

    def _check_comparison_types(
        result: ArrayLike | bool, a: ArrayLike, b: Scalar | Pattern
    ) -> None:
        """
        Raises an error if the two arrays (a,b) cannot be compared.
        Otherwise, returns the comparison result as expected.
        """
        if is_bool(result) and isinstance(a, np.ndarray):
            type_names = [type(a).__name__, type(b).__name__]

            type_names[0] = f"ndarray(dtype={a.dtype})"

            raise TypeError(
                f"Cannot compare types {type_names[0]!r} and {type_names[1]!r}"
            )

    if not regex or not should_use_regex(regex, b):
        # TODO: should use missing.mask_missing?
        op = lambda x: operator.eq(x, b)
    else:
        op = np.vectorize(
            lambda x: (
                bool(re.search(b, x))
                if isinstance(x, str) and isinstance(b, (str, Pattern))
                else False
            ),
            otypes=[bool],
        )

    # GH#32621 use mask to avoid comparing to NAs
    if isinstance(a, np.ndarray) and mask is not None:

View on GitHub (pinned to 3b7651241d)

Solutions

  1. Apply replace per column so each comparison is type-compatible.
  2. Cast the value to match the column dtype before replacing.
  3. Use a regex pattern only on string columns and a separate numeric value on numeric columns.

Example fix

# before
df.replace(re.compile('x'), 0)  # on a numeric df
# after
df.apply(lambda c: c.replace(re.compile('x'), 0) if c.dtype == 'object' else c)
Defensive patterns

Strategy: validation

Validate before calling

def safe_replace(df, to_replace, value):
    # apply per column so each comparison is type-compatible
    out = df.copy()
    for col in out.columns:
        try:
            out[col] = out[col].replace(to_replace, value)
        except TypeError:
            continue
    return out

Try / catch

try:
    df.replace(to_replace, value)
except TypeError as e:
    if 'Cannot compare types' in str(e):
        df.apply(lambda c: c.replace(to_replace, value) if c.dtype == 'object' else c)
    else:
        raise

Prevention

When it happens

Trigger: df.replace(non_comparable_value, new_value) where the value's type can't be compared to the column dtype (e.g. replacing a complex number in a string column); regex=False comparisons between incompatible types.

Common situations: Looping replace over heterogeneous columns with a single value list; passing None or an unsupported scalar type to replace on a numeric frame.

Related errors


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