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
- Wrap the list in a Series: s.search_sorted(pl.Series([1, 5, 10]))
- Or wrap in a literal expression: s.search_sorted(pl.lit([1, 5, 10]))
- 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
- Always construct pl.Series(...) for batch lookups instead of passing raw lists
- Lint/guard call sites that forward dynamic values into search_sorted
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
- {how!r} strategy is not supported for {qualified_type_name(e
- {type(self).__name__!r} object has no attribute {name!r}
- activate 'dtype-array'
- Deserialization from JSON not implemented for {adt:?}
- list.to_struct() got a str instead of a list. hint: pass ['{
AI-assisted analysis of pola-rs/polars@68506541d2 (2026-08-28).
Data as JSON: /api/errors/fec39b6b4180fb3f.
Report an issue: GitHub.