roboflow/supervision · error · ValueError
epsilon_step must be positive.
Error message
epsilon_step must be positive.
What it means
Raised by approximate_polygon when the epsilon_step argument is zero or negative. epsilon_step controls how much the Douglas-Peucker tolerance grows on each iteration of the loop that simplifies the polygon toward the target point count. A non-positive step would make no progress (infinite loop) or move backward, so it is rejected up front.
Source
Thrown at src/supervision/detection/utils/polygons.py:114
>>> 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 = candidate
return approximated_pointsView on GitHub (pinned to 7f254d9784)
Solutions
- Pass a small positive step such as epsilon_step=0.1 (the loop increments by this value each iteration).
- If the step is computed dynamically, clamp it: epsilon_step = max(epsilon_step, 0.1).
- If you do not want simplification at all, skip the call or pass percentage=0 (with a valid positive step) — the function already returns the polygon unchanged when it is at or below the target point count.
Example fix
// before approximate_polygon(poly, percentage=0.5, epsilon_step=0) // after approximate_polygon(poly, percentage=0.5, epsilon_step=0.1)
Defensive patterns
Strategy: validation
Validate before calling
epsilon_step = max(float(epsilon_step), 0.1) result = approximate_polygon(polygon, percentage=0.5, epsilon_step=epsilon_step)
Type guard
def is_valid_epsilon_step(v: float) -> bool:
return float(v) > 0 Try / catch
try:
simplified = approximate_polygon(poly, percentage=p, epsilon_step=e)
except ValueError as err:
if 'epsilon_step' in str(err):
simplified = approximate_polygon(poly, percentage=p, epsilon_step=0.1)
else:
raise Prevention
- Never use 0 to mean 'no simplification' — percentage=0 with a positive step already returns small polygons unchanged.
- When deriving epsilon_step from image scale, clamp with max(step, 0.1).
When it happens
Trigger: Calling supervision.detection.utils.polygons.approximate_polygon(polygon, percentage=0.5, epsilon_step=0) or with a negative epsilon_step. Also reachable via any pipeline that computes epsilon_step dynamically (e.g. proportional to box area) and lets it round down to 0 for tiny polygons.
Common situations: Passing 0 expecting 'no simplification' semantics; deriving epsilon_step from image scale so that very small regions produce 0; copy-pasting a default of 0 from another API where 0 means 'auto'.
Related errors
- module {__name__} has no attribute {name}
- Edge indices must use the 1-based convention and be within t
- sigma must contain at least one value
- All sigma values must be positive
- max_axis must be positive when provided
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/4609b1dff7e0afd6.
Report an issue: GitHub.