pola-rs/polars · error · ValueError
`percentiles` must all be in the range [0, 1]
Error message
`percentiles` must all be in the range [0, 1]
What it means
ValueError from parse_percentiles (py-polars/src/polars/_utils/various.py:588-603). LazyFrame.describe(percentiles=...) (and any API routing through parse_percentiles) requires every supplied percentile to be a fraction in the closed interval [0.0, 1.0]; polars then internally injects the median (0.5) and sorts the list. Values outside [0, 1] — most commonly whole-number percentages like 50 or 95 — raise immediately.
Source
Thrown at py-polars/src/polars/_utils/various.py:603
return False
def parse_percentiles(
percentiles: Sequence[float] | float | None, *, inject_median: bool = False
) -> Sequence[float]:
"""
Transforms raw percentiles into our preferred format, adding the 50th percentile.
Raises a ValueError if the percentile sequence is invalid
(e.g. outside the range [0, 1])
"""
if isinstance(percentiles, float):
percentiles = [percentiles]
elif percentiles is None:
percentiles = []
if not all((0 <= p <= 1) for p in percentiles):
msg = "`percentiles` must all be in the range [0, 1]"
raise ValueError(msg)
sub_50_percentiles = sorted(p for p in percentiles if p < 0.5)
at_or_above_50_percentiles = sorted(p for p in percentiles if p >= 0.5)
if inject_median and (
not at_or_above_50_percentiles or at_or_above_50_percentiles[0] != 0.5
):
at_or_above_50_percentiles = [0.5, *at_or_above_50_percentiles]
return [*sub_50_percentiles, *at_or_above_50_percentiles]
def re_escape(s: str) -> str:
"""Escape a string for use in a Polars (Rust) regex."""
# note: almost the same as the standard python 're.escape' function, but
# escapes _only_ those metachars with meaning to the rust regex crate
re_rust_metachars = r"\\?()|\[\]{}^$#&~.+*-"
return re.sub(f"([{re_rust_metachars}])", r"\\\1", s)View on GitHub (pinned to df599052da)
Solutions
- Convert percentages to fractions: divide by 100 ([50, 95] -> [0.5, 0.95])
- Drop the value entirely if you meant the median — 0.5 is injected automatically
- Validate user input before the call: assert all(0 <= p <= 1 for p in percentiles)
Example fix
# before lf.describe(percentiles=[10, 50, 90]) # ValueError # after lf.describe(percentiles=[0.10, 0.50, 0.90])
Defensive patterns
Strategy: validation
Validate before calling
def norm_percentiles(ps: list[float]) -> list[float]:
out = [p / 100 if p > 1 else p for p in ps]
if not all(0.0 <= p <= 1.0 for p in out):
raise ValueError('percentiles must be fractions in [0, 1]')
return out Prevention
- Normalize 0-100 style inputs by dividing by 100 before calling describe
- 0.5 is auto-injected — don't pass the median explicitly
- Validate user-facing percentile settings at the config boundary
When it happens
Trigger: lf.describe(percentiles=[0.1, 50, 0.9]); lf.describe(percentiles=95); negative values or values > 1 such as [1.5].
Common situations: Copy-pasting percentile integers from configure-style tooling or report specs ('show the 95th percentile'); mixing units with APIs that take 0-100 (some plotting/reporting libs); user-facing knobs forwarded unvalidated.
Related errors
- index positions should be smaller than 2^32
- index positions should be greater than or equal to -2^32
- Can't patch loop of type %s
- negative stop is not supported for lazy slices
- negative stride is not supported in conjunction with start+s
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/f827055a4fac44c5.
Report an issue: GitHub.