odysseus-dev/odysseus · warning · HTTPException
Box must be [x1, y1, x2, y2]
Error message
Box must be [x1, y1, x2, y2]
What it means
HTTP 400 from SAM mask box validation: the 'box' field must be a JSON list of exactly 4 numbers ([x1, y1, x2, y2]). A tuple-like object, a dict, a string, or a list of length != 4 fails the isinstance/len check before any float conversion is attempted.
Source
Thrown at routes/gallery/gallery_routes.py:1880
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(),
inputs["reshaped_input_sizes"].detach().cpu(),
)
mask_tensor = masks[0]
while getattr(mask_tensor, "ndim", 0) > 3:
mask_tensor = mask_tensor[0]View on GitHub (pinned to f9235ebbf1)
Solutions
- Send box as a flat 4-element numeric array: [x1, y1, x2, y2]
- Slice detection outputs to the first 4 elements before sending: box = det.box[:4]
- Verify no wrapper nesting like box=[[0,0,100,200]] — the server adds its own nesting for the processor
Example fix
# before
box = {"x1": 10, "y1": 20, "x2": 110, "y2": 220}
# after
box = [10, 20, 110, 220] Defensive patterns
Strategy: validation
Validate before calling
def is_valid_box(box) -> bool:
return isinstance(box, list) and len(box) == 4 and all(
isinstance(v, (int, float)) and not isinstance(v, bool) for v in box
)
assert is_valid_box(body.get("box")), 'box must be [x1, y1, x2, y2]' Type guard
function isBox4(v: unknown): v is [number, number, number, number] {
return Array.isArray(v) && v.length === 4 && v.every(n => typeof n === 'number' && Number.isFinite(n));
} Prevention
- Slice detector outputs to exactly four elements (drop any 5th confidence value) before sending
- Keep boxes as flat numeric arrays end-to-end; never store them as objects in client state
- Remember the server adds the nesting the SAM processor needs — send one flat array, not [[...]]
When it happens
Trigger: POST with box={"x1":0,...} (dict), box=[0,0,100] (3 elements), box=[0,0,100,200,5] (5 elements), or box="0,0,100,200" (string).
Common situations: Client stores the box as an object; box assembled from a bbox that sometimes returns None or an extra confidence element (e.g. [x1,y1,x2,y2,score]); grounding pipeline appending a score as a 5th value.
Related errors
- Provide at least one point, box, or object text
- Invalid box format
- No documents specified
- Invalid point format
- content is required
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/0216376901734547.
Report an issue: GitHub.