pola-rs/polars · error · InvalidOperationError

passing a list to `search_sorted` is ambiguous; use `Series.

Error message

passing a list to `search_sorted` is ambiguous; use `Series.search_sorted(pl.Series([...]), ...)` or `Series.search_sorted(pl.lit(...), ...)`

What it means

Series.search_sorted dispatches differently depending on whether the searched element is a scalar, a Series, an expression, or a numpy array, and each returns a different shape (scalar vs Series). Passing a plain Python list is ambiguous — Polars cannot know whether you want element-wise results or a single value — so it raises InvalidOperationError.

Source

Thrown at py-polars/src/polars/series/series.py:3913

        Series: 'set' [u32]
        [
            0
            3
            5
        ]
        >>> # To search for a list of values in a series, of lists, use pl.lit():
        >>> list_s = pl.Series("lists", [[0, 1], [0, 2], [1, 4]])
        >>> list_s.search_sorted(pl.lit([0, 2]), "left")
        shape: (1,)
        Series: 'lists' [u32]
        [
            1
        ]
        """
        df = F.select(F.lit(self).search_sorted(element, side, descending=descending))
        if isinstance(element, list):
            msg = "passing a list to `search_sorted` is ambiguous; use `Series.search_sorted(pl.Series([...]), ...)` or `Series.search_sorted(pl.lit(...), ...)`"
            raise InvalidOperationError(msg)
        elif isinstance(element, (Series, pl.Expr)):
            return df.to_series()
        elif _check_for_numpy(element) and isinstance(element, np.ndarray):
            return df.to_series()
        else:
            return df.item()

    def unique(self, *, maintain_order: bool = False) -> Series:
        """
        Get unique elements in series.

        `null` is considered to be a unique value for the purposes of this operation.

        Parameters
        ----------
        maintain_order
            Maintain order of data. This requires more work.

View on GitHub (pinned to 68506541d2)

Solutions

  1. Wrap the list in a Series: s.search_sorted(pl.Series([1, 5, 10]))
  2. Or wrap in a literal expression: s.search_sorted(pl.lit([1, 5, 10]))
  3. For a single value, pass the scalar directly (not a one-element list)

Example fix

# before
s.search_sorted([1, 5, 10])

# after
s.search_sorted(pl.Series([1, 5, 10]))
Defensive patterns

Strategy: type-guard

Validate before calling

element = pl.Series(element) if isinstance(element, list) else element
result = s.search_sorted(element, side='any')

Type guard

def is_searchable(e: object) -> bool:
    return e is None or isinstance(e, (int, float, str, pl.Series, pl.Expr)) or (
        _check_for_numpy(e) and isinstance(e, np.ndarray)
    )

Try / catch

try:
    result = s.search_sorted(element, side)
except pl.exceptions.InvalidOperationError as e:
    if 'ambiguous' in str(e):
        result = s.search_sorted(pl.Series(element), side)
    else:
        raise

Prevention

When it happens

Trigger: Calling Series.search_sorted with a Python list, e.g. s.search_sorted([1, 5, 10]) or with side/descending arguments and a list element.

Common situations: Developers coming from numpy's searchsorted or bisect who naturally pass a list of needles; batch lookup code that builds a list dynamically instead of a Series; refactors from scalar lookups to batch lookups.

Related errors


AI-assisted analysis of pola-rs/polars@68506541d2 (2026-08-28). Data as JSON: /api/errors/fec39b6b4180fb3f. Report an issue: GitHub.