TheAlgorithms/Python · error · ValueError
graham_scan: argument must contain more than 3 points.
Error message
graham_scan: argument must contain more than 3 points.
What it means
Raised by graham_scan when the input list has 2 or fewer points, because a convex hull is undefined (a point or a segment has no hull). Note the guard is len(points) <= 2 while exactly 3 points are returned as-is, so despite the message wording the real requirement is at least 3 points.
Source
Thrown at other/graham_scan.py:115
:return: The points on convex hell.
Examples:
>>> graham_scan([(9, 6), (3, 1), (0, 0), (5, 5), (5, 2), (7, 0), (3, 3), (1, 4)])
[(0, 0), (7, 0), (9, 6), (5, 5), (1, 4)]
>>> graham_scan([(0, 0), (1, 0), (1, 1), (0, 1)])
[(0, 0), (1, 0), (1, 1), (0, 1)]
>>> graham_scan([(0, 0), (1, 1), (2, 2), (3, 3), (-1, 2)])
[(0, 0), (1, 1), (2, 2), (3, 3), (-1, 2)]
>>> graham_scan([(-100, 20), (99, 3), (1, 10000001), (5133186, -25), (-66, -4)])
[(5133186, -25), (1, 10000001), (-100, 20), (-66, -4)]
"""
if len(points) <= 2:
# There is no convex hull
raise ValueError("graham_scan: argument must contain more than 3 points.")
if len(points) == 3:
return points
# find the lowest and the most left point
minidx = 0
miny, minx = maxsize, maxsize
for i, point in enumerate(points):
x = point[0]
y = point[1]
if y < miny:
miny = y
minx = x
minidx = i
if y == miny and x < minx:
minx = x
minidx = i
# remove the lowest and the most left point from points for preparing for sort
points.pop(minidx)View on GitHub (pinned to f5988cc097)
Solutions
- Check len(points) >= 3 before calling graham_scan and skip/short-circuit degenerate inputs
- Filter or assert upstream so the point set never degenerates below 3 points
- For exactly 3 points be aware the function returns them unsorted and without collinearity handling
Example fix
# before hull = graham_scan(points) # ValueError when points has <= 2 entries # after hull = graham_scan(points) if len(points) >= 3 else list(points)
Defensive patterns
Strategy: validation
Validate before calling
def has_hull(points) -> bool:
return len(points) >= 3 Type guard
from typing import Sequence
def is_scannable_point_set(points: Sequence[Sequence[float]]) -> bool:
"""True when graham_scan can process the input."""
return len(points) >= 3 and all(len(p) >= 2 for p in points) Try / catch
try:
hull = graham_scan(points)
except ValueError as e:
if 'more than 3 points' in str(e):
hull = list(points) # degenerate set: points are their own 'hull'
else:
raise Prevention
- Filter point clouds to at least 3 distinct points before running hull algorithms
- Unit-test geometry pipelines with empty, single, and duplicate-point inputs
When it happens
Trigger: Calling graham_scan([(0,0)]), graham_scan([(0,0),(1,1)]), or graham_scan([]) — any list of 0, 1, or 2 (x, y) tuples.
Common situations: Running the scan over dynamically generated point clouds (clusters, filtered outliers) that can degenerate to one or two points, or feeding edge-case test data into a computational-geometry pipeline.
Related errors
- Expecting a list of points but got {points}
- Expected a_coeffs to have {self.order + 1} elements for {sel
- Expected b_coeffs to have {self.order + 1} elements for {sel
- k must not be negative
- n must not be negative
AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14).
Data as JSON: /api/errors/00fbd7fade309d0a.
Report an issue: GitHub.