odysseus-dev/odysseus · warning · HTTPException
Invalid point format
Error message
Invalid point format
What it means
HTTP 400 raised while parsing the points array of a SAM mask request. Each point must be an object with numeric 'x'/'y' keys and an optional integer 'label'; float()/int() conversion failing (missing key, string like 'abc', None, nested list) triggers this. The original exception is chained with 'from exc'.
Source
Thrown at routes/gallery/gallery_routes.py:1875
if not points and not box:
raise HTTPException(400, "Provide at least one point, box, or object text")
backend = _load_sam_backend()
torch = backend["torch"]
processor = backend["processor"]
model = backend["model"]
device = backend["device"]
kwargs: Dict[str, Any] = {"return_tensors": "pt"}
input_points = []
if points:
input_labels = []
for p in points:
try:
input_points.append([float(p["x"]), float(p["y"])])
input_labels.append(int(p.get("label", 1)))
except Exception as exc:
raise HTTPException(400, "Invalid point format") from exc
kwargs["input_points"] = [input_points]
kwargs["input_labels"] = [input_labels]
if box:
if not isinstance(box, list) or len(box) != 4:
raise HTTPException(400, "Box must be [x1, y1, x2, y2]")
try:
kwargs["input_boxes"] = [[[float(v) for v in box]]]
except Exception as exc:
raise HTTPException(400, "Invalid box format") from exc
try:
inputs = processor(image, **kwargs)
model_inputs = _model_inputs_to_device(inputs, device, torch)
with torch.no_grad():
outputs = model(**model_inputs)
masks = processor.image_processor.post_process_masks(
outputs.pred_masks.detach().cpu(),
inputs["original_sizes"].detach().cpu(),View on GitHub (pinned to f9235ebbf1)
Solutions
- Send each point as {"x": <number>, "y": <number>, "label": 0|1}
- Strip units like 'px' and Number()-cast coordinates in the client before sending
- Validate the points array client-side before issuing the request
Example fix
// before
points: [[120, 80], [200, 150]]
// after
points: [{ x: 120, y: 80, label: 1 }, { x: 200, y: 150, label: 1 }] Defensive patterns
Strategy: type-guard
Validate before calling
def normalize_points(points):
out = []
for p in points or []:
out.append({
"x": float(p["x"]),
"y": float(p["y"]),
"label": int(p.get("label", 1)),
})
return out # raises before the request if malformed Type guard
function isValidPoint(p: unknown): p is { x: number; y: number; label?: number } {
if (typeof p !== 'object' || p === null) return false;
const { x, y, label } = p as Record<string, unknown>;
return Number.isFinite(Number(x)) && Number.isFinite(Number(y))
&& (label === undefined || Number.isInteger(Number(label)));
}
const ok = points.every(isValidPoint); Try / catch
try:
resp = client.post(mask_url, json=payload)
except HTTPError as e:
if e.response.status_code == 400 and 'point format' in e.response.text:
payload['points'] = normalize_points(payload['points'])
resp = client.post(mask_url, json=payload)
else:
raise Prevention
- Type the points array in the client (TS interface or pydantic model) so malformed shapes fail at compile/validation time
- Convert click-event coordinates with Number() and strip CSS units before adding to the array
- Write a unit test asserting a legacy [x, y] tuple payload is rejected client-side
When it happens
Trigger: POST with points=[{"x": "abc"}], points=[[120, 80]] (array instead of object), point missing the 'y' key, or label set to "foreground" instead of 0/1.
Common situations: Frontend migrating from an older [x, y] tuple format to the {x, y} object format; label sent as a string; coordinates serialized as None after a null click; client code passing pixel strings from CSS values (e.g. '120px').
Related errors
- Invalid box format
- {key} must be an integer
- Provide at least one point, box, or object text
- Box must be [x1, y1, x2, y2]
- await res.text()
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/4b12c7df826ed46c.
Report an issue: GitHub.