{"record":{"id":"341045e2b13207a2","repo":"pola-rs/polars","slug":"series-of-type-self-dtype-does-not-have-op-ope","errorCode":null,"errorMessage":"Series of type {self.dtype} does not have {op} operator","messagePattern":"Series of type (.+?) does not have (.+?) operator","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/series/series.py","lineNumber":921,"sourceCode":"            assert f is not None\n            return self._from_pyseries(f(d))\n\n        if isinstance(other, Sequence) and not isinstance(other, str):\n            if self.dtype in (List, Array):\n                other = [other]\n            other = Series(\"\", other)\n            if other.dtype == Null:\n                other.cast(self.dtype)\n\n        if isinstance(other, Series):\n            return self._from_pyseries(getattr(self._s, op)(other._s))\n        try:\n            f = get_ffi_func(op + \"_<>\", self.dtype, self._s)\n        except NotImplementedError:\n            f = None\n        if f is None:\n            msg = f\"Series of type {self.dtype} does not have {op} operator\"\n            raise NotImplementedError(msg)\n        if other is not None:\n            other = maybe_cast(other, self.dtype)\n\n        return self._from_pyseries(f(other))\n\n    @overload  # type: ignore[override]\n    def __eq__(self, other: Expr) -> Expr: ...  # type: ignore[overload-overlap]\n\n    @overload\n    def __eq__(self, other: object) -> Series: ...\n\n    def __eq__(self, other: object) -> Series | Expr:\n        warn_null_comparison(other)\n        if isinstance(other, pl.Expr):\n            return F.lit(self).__eq__(other)\n        return self._comp(other, \"eq\")\n\n    @overload  # type: ignore[override]","sourceCodeStart":903,"sourceCodeEnd":939,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/series/series.py#L903-L939","documentation":"Raised in Series._comp (py-polars/src/polars/series/series.py:921) when no FFI comparison kernel exists for the Series dtype and the given scalar op. After the special scalar paths (datetime/time/float upcast/boolean/etc.) are exhausted, polars looks up a native eq/neq/gt/ge/lt/le kernel for self.dtype; nested dtypes (List/Array/Struct), Object, and some others have none, so the comparison raises NotImplementedError naming the dtype and operator.","triggerScenarios":"pl.Series([[1, 2], [3]], dtype=pl.List(pl.Int64)) == 1 (scalar compare against a List Series); struct Series == something; Object-dtype Series == value. Note Series-to-Series comparison goes through a different branch, so s == pl.Series(...) may not hit this.","commonSituations":"Comparing nested columns to scalars expecting elementwise containment (a pandas-like reflex); testing Object columns; equality checks on struct columns. The right tool is usually a dtype-specific namespace or an expression.","solutions":["For list containment: s.list.contains(1) instead of s == 1","For struct fields: compare the field via s.struct.field(\"name\") == value","Use expressions: df.select(pl.col(\"col\") == value) or filter with the appropriate expr (list/struct namespaces)","Cast Object columns to a concrete dtype if possible before comparing"],"exampleFix":"# before\ns = pl.Series([[1, 2], [3]], dtype=pl.List(pl.Int64))\ns == 1  # NotImplementedError\n\n# after\ns.list.contains(1)  # elementwise: does each list contain 1?","handlingStrategy":"fallback","validationCode":"import polars as pl\n\ndef compare_safe(s: pl.Series, value):\n    if s.dtype.base_type() in (pl.List, pl.Array, pl.Struct, pl.Object):\n        raise TypeError(f\"no scalar comparison for {s.dtype}; use list/struct namespace\")\n    return s == value","typeGuard":"def has_scalar_comparison(s: pl.Series) -> bool:\n    return s.dtype.base_type() not in (pl.List, pl.Array, pl.Struct, pl.Object, pl.Null)","tryCatchPattern":"try:\n    mask = s == value\nexcept NotImplementedError as e:\n    if \"does not have\" in str(e) and s.dtype.base_type() in (pl.List, pl.Array):\n        mask = s.list.contains(value)\n    else:\n        raise","preventionTips":["Use s.list.contains(x) for list membership, s.struct.field(...) for struct fields","Prefer expression context (df.filter(pl.col(...)...)) where nested comparisons are explicit","Cast Object columns to concrete dtypes as soon as possible"],"tags":["polars","series","comparison","nested-dtype","notimplementederror"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}