roboflow/supervision · error · ValueError
Callback returned {len(detections_in_slices)} Detections for
Error message
Callback returned {len(detections_in_slices)} Detections for {len(offsets)} slices. Lengths must match. What it means
Raised by InferenceSlicer's batch path when the callback's returned list length differs from the number of image slices passed in. The slicer must zip each returned Detections with its slice offset to map detections back into full-image coordinates; a mismatched length breaks that 1:1 alignment, so it fails instead of silently dropping or misplacing detections.
Source
Thrown at src/supervision/detection/tools/inference_slicer.py:591
with self._raster_read_lock:
bands = image.read(window=window)
slices.append(np.ascontiguousarray(np.transpose(bands, (1, 2, 0))))
resolution_wh = (image.width, image.height)
else:
slices = [crop_image(image=image, xyxy=offset) for offset in offsets]
resolution_wh = get_image_resolution_wh(image)
batch_callback = cast(
Callable[[list[npt.NDArray[Any]]], list[Detections]], self.callback
)
detections_in_slices = batch_callback(slices)
if not isinstance(detections_in_slices, list):
raise ValueError(
"Callback must return `list[Detections]` when `batch_size > 1`. "
f"Got: {type(detections_in_slices)}"
)
if len(detections_in_slices) != len(offsets):
raise ValueError(
f"Callback returned {len(detections_in_slices)} Detections "
f"for {len(offsets)} slices. Lengths must match."
)
if self.compact_masks:
for det, image_slice in zip(detections_in_slices, slices):
if det.mask is not None and isinstance(det.mask, np.ndarray):
slice_w, slice_h = get_image_resolution_wh(image_slice)
full_slice_xyxy = np.tile(
np.array([[0, 0, slice_w - 1, slice_h - 1]], dtype=np.float64),
(len(det), 1),
)
det.mask = CompactMask.from_dense(
det.mask,
full_slice_xyxy,
image_shape=(slice_h, slice_w),
)
View on GitHub (pinned to 7f254d9784)
Solutions
- Always return exactly one Detections (possibly empty, sv.Detections.empty()) per input image, in input order.
- If the model API can skip images, index-pad the results back to the input length before returning.
- Do not filter slices inside the callback — filtering happens later via the slicer's overlap/NMS stages.
Example fix
# before
def callback(images):
return [sv.Detections.from_ultralytics(r) for r in model.predict(images) if len(r.boxes) > 0]
# after
def callback(images):
return [sv.Detections.from_ultralytics(r) for r in model.predict(images)] # empty slices yield empty Detections Defensive patterns
Strategy: validation
Validate before calling
def batch_callback(images):
results = model.predict(images, verbose=False)
if len(results) != len(images):
raise RuntimeError(f'model returned {len(results)} results for {len(images)} images')
return [sv.Detections.from_ultralytics(r) for r in results] Type guard
def matches_slice_count(result, images) -> bool:
return isinstance(result, list) and len(result) == len(images) Try / catch
try:
detections = slicer(image)
except ValueError as err:
if 'Lengths must match' in str(err):
raise RuntimeError('batch callback must return one Detections per input slice') from err
raise Prevention
- Never filter empty results inside the callback — return sv.Detections.empty() for empty slices.
- Assert len(results) == len(images) right after the model call for a clearer failure point.
When it happens
Trigger: A batch callback that returns model predictions for a filtered subset (e.g. only images with detections), or a predict call that returns fewer Results than inputs (some backends skip failed images), or returning e.g. results[:-1] by an off-by-one bug.
Common situations: Callbacks that filter empty results; batched inference wrappers that deduplicate or drop failed items; misunderstanding that one Detections per input slice is required even when a slice has zero detections.
Related errors
- Callback must return `list[Detections]` when `batch_size > 1
- `batch_size` must be a positive integer. Received: {batch_si
- `slice_wh` must be an int or a tuple of two positive integer
- `overlap_wh` must be an int or a tuple of two non negative i
- Resolution width and height are required for moving segmenta
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/a6d95989725d7815.
Report an issue: GitHub.