roboflow/supervision · error · ValueError
Percentage must be in the range [0, 1).
Error message
Percentage must be in the range [0, 1).
What it means
`sv.approximate_polygon(polygon, percentage, epsilon_step)` simplifies a polygon by removing a fraction of its points via Ramer-Douglas-Peucker; `percentage` is that fraction and must lie in [0, 1). This ValueError fires for negative values or values >= 1 — a percentage of 1 would mean removing all points (a polygon needs at least 3), and negative removal is meaningless. Note the value is a fraction, not 0-100.
Source
Thrown at src/supervision/detection/utils/polygons.py:112
>>> polygon = np.array([[0, 0], [10, 0], [10, 10], [0, 10],
... [5, 10], [5, 5], [3, 7], [1, 9]])
>>> result = approximate_polygon(polygon, percentage=0.5)
>>> result.shape[1]
2
>>> len(result) <= max(int(len(polygon) * 0.5), 3)
True
Polygon already at or below target — returned unchanged:
>>> tiny = np.array([[0, 0], [5, 0], [2, 4]])
>>> approximate_polygon(tiny, percentage=0.5) is tiny
True
```
"""
if percentage < 0 or percentage >= 1:
raise ValueError("Percentage must be in the range [0, 1).")
if epsilon_step <= 0:
raise ValueError("epsilon_step must be positive.")
target_points = max(int(len(polygon) * (1 - percentage)), 3)
if len(polygon) <= target_points:
return polygon
epsilon: float = 0
approximated_points = polygon
while len(approximated_points) > target_points:
epsilon += epsilon_step
candidate = np.squeeze(cv2.approxPolyDP(polygon, epsilon, closed=True), axis=1)
# Stop before the approximation collapses below a valid polygon; keep the
# last result with at least three points.
if len(candidate) < 3:
break
approximated_points = candidateView on GitHub (pinned to 7f254d9784)
Solutions
- Express the fraction in [0, 1): use 0.5 for 'remove half the points', not 50.
- Clamp computed values: `percentage = min(max(percentage, 0.0), 0.999)`.
- Convert from a 0-100 scale: `percentage = pct_100 / 100.0`.
Example fix
# before small = sv.approximate_polygon(polygon, percentage=30) # meant 30% # after small = sv.approximate_polygon(polygon, percentage=0.3)
Defensive patterns
Strategy: validation
Validate before calling
if not 0 <= percentage < 1:
percentage = min(max(percentage / 100.0 if percentage > 1 else percentage, 0.0), 0.999)
result = sv.approximate_polygon(polygon, percentage=percentage) Type guard
def is_valid_percentage(v) -> bool:
return isinstance(v, (int, float)) and 0 <= v < 1 Prevention
- Treat percentage as a 0-1 fraction; divide by 100 when it comes from a UI slider.
- Clamp computed fractions to [0, 0.999] to absorb rounding.
When it happens
Trigger: Calling `approximate_polygon(poly, percentage=50)` intending 50 percent (50 is far outside [0,1)); passing `percentage=1.0` to drop every point; computing the fraction dynamically and letting rounding push it to exactly 1.0 or below 0.
Common situations: Confusing the 0-1 fraction convention with a 0-100 scale; UI sliders that emit percentages 0-100 forwarded verbatim; derived values like `1 - keep_ratio` where keep_ratio rounds to 0.
Related errors
- starting_image_id and starting_annotation_id must be >= 1 (C
- The magnitude of the vector cannot be zero.
- overlap_metric {overlap_metric} is not supported, only 'IOU'
- Invalid value: {value}. Must be one of {cls.list()}
- epsilon_step must be positive.
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/abc8d823ecac1550.
Report an issue: GitHub.