pola-rs/polars · error · TooManyRowsReturnedError
predicate <{by_predicate!s}> returned {n_rows} rows
Error message
predicate <{by_predicate!s}> returned {n_rows} rows What it means
When DataFrame.row(by_predicate=expr) runs, the frame is filtered with the predicate and the number of surviving rows is counted. If more than one row matches, the call is ambiguous and polars raises TooManyRowsReturnedError (a polars.exceptions subclass), including the predicate text and the row count in the message.
Source
Thrown at py-polars/src/polars/dataframe/frame.py:11883
msg = "expressions should be passed to the `by_predicate` parameter"
raise TypeError(msg)
if index is not None:
row = self._df.row_tuple(index)
if named:
return dict(zip(self.columns, row, strict=True))
else:
return row
elif by_predicate is not None:
if not isinstance(by_predicate, pl.Expr):
msg = f"expected `by_predicate` to be an expression, got {qualified_type_name(by_predicate)!r}"
raise TypeError(msg)
rows = self.filter(by_predicate).rows()
n_rows = len(rows)
if n_rows > 1:
msg = f"predicate <{by_predicate!s}> returned {n_rows} rows"
raise TooManyRowsReturnedError(msg)
elif n_rows == 0:
msg = f"predicate <{by_predicate!s}> returned no rows"
raise NoRowsReturnedError(msg)
row = rows[0]
if named:
return dict(zip(self.columns, row, strict=True))
else:
return row
else:
msg = "one of `index` or `by_predicate` must be set"
raise ValueError(msg)
@overload
def rows(self, *, named: Literal[False] = ...) -> list[tuple[Any, ...]]: ...
@overload
def rows(self, *, named: Literal[True]) -> list[dict[str, Any]]: ...View on GitHub (pinned to df599052da)
Solutions
- Make the predicate uniquely identifying — add conditions until exactly one row matches (composite key: (pl.col('a') == x) & (pl.col('b') == y))
- If any match is acceptable, select deterministically: df.filter(pred).head(1).row(0) or .row(index=0) after sorting
- Deduplicate the source or enforce uniqueness upstream (unique(subset=..., keep='first')) before doing key lookups
- Catch polars.exceptions.TooManyRowsReturnedError to handle ambiguous keys explicitly
Example fix
# before
row = df.row(by_predicate=pl.col('user_id') == 7) # duplicates -> TooManyRowsReturnedError
# after
row = df.filter(pl.col('user_id') == 7).head(1).row(0)
# or make the key unique:
# row = df.row(by_predicate=(pl.col('user_id') == 7) & (pl.col('valid_to').is_null())) Defensive patterns
Strategy: try-catch
Validate before calling
matched = df.filter(by_predicate)
if matched.height != 1:
raise ValueError(f'predicate matched {matched.height} rows; expected exactly 1')
row = matched.row(0) Try / catch
from polars.exceptions import TooManyRowsReturnedError
try:
row = df.row(by_predicate=pred)
except TooManyRowsReturnedError:
# duplicate keys: pick deterministically or surface the ambiguity
matched = df.filter(pred).sort(key_col)
row = matched.head(1).row(0) Prevention
- Deduplicate lookup sources (unique(subset=key_cols, keep='first')) before key-based row() calls
- Prefer composite-key predicates that are unique by construction
- Where any-match suffices, use df.filter(pred).head(1).row(0) instead of row(by_predicate=...)
When it happens
Trigger: df.row(by_predicate=pl.col('category') == 'x') where several rows share the category; key lookups on data with duplicate keys (non-unique IDs, repeated timestamps); predicates that are always true, e.g. pl.col('flag') | ~pl.col('flag') or comparing against a value present in many rows.
Common situations: Reference/config tables that unexpectedly contain duplicate keys after an upstream merge or reload; time-series lookups where timestamps repeat; assuming a column is unique without a constraint.
Related errors
- predicate <{by_predicate!s}> returned no rows
- can only call `.row()` without "index" or "by_predicate" val
- cannot set both 'index' and 'by_predicate'; mutually exclusi
- expressions should be passed to the `by_predicate` parameter
- expected `by_predicate` to be an expression, got {qualified_
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/0c86363704690851.
Report an issue: GitHub.