roboflow/supervision · error · ValueError
Callback must return `list[Detections]` when `batch_size > 1
Error message
Callback must return `list[Detections]` when `batch_size > 1`. Got: {type(detections_in_slices)} What it means
Raised by InferenceSlicer's batch path when the callback returns something other than a list while batch_size > 1. In batch mode the callback receives a list of image slices and must return a list with exactly one Detections object per slice; a single Detections (the single-image contract) or any other type cannot be aligned with the slices.
Source
Thrown at src/supervision/detection/tools/inference_slicer.py:586
if _is_windowed_raster(image):
slices = []
for offset in offsets:
x_min, y_min, x_max, y_max = (int(v) for v in offset)
window = ((y_min, y_max), (x_min, x_max))
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(View on GitHub (pinned to 7f254d9784)
Solutions
- Rewrite the callback for batching: accept a list of images, return [sv.Detections.from_ultralytics(r) for r in model.predict(images, ...)] — one entry per input image, in order.
- Alternatively keep the single-image callback and set batch_size=1 (the default).
- Ensure the list length equals the input length — see the companion length-mismatch error.
Example fix
# before
def callback(image):
return sv.Detections.from_ultralytics(model.predict(image, verbose=False)[0])
slicer = sv.InferenceSlicer(callback=callback, batch_size=8)
# after
def callback(images):
results = model.predict(images, verbose=False)
return [sv.Detections.from_ultralytics(r) for r in results]
slicer = sv.InferenceSlicer(callback=callback, batch_size=8) Defensive patterns
Strategy: type-guard
Validate before calling
def is_batch_callback(cb, n=2) -> bool:
import numpy as np
probe = [np.zeros((8, 8, 3), dtype=np.uint8) for _ in range(n)]
result = cb(probe)
return isinstance(result, list) and len(result) == n
if batch_size > 1 and not is_batch_callback(callback):
batch_size = 1
slicer = sv.InferenceSlicer(callback=callback, batch_size=batch_size) Type guard
def returns_detections_list(fn) -> bool:
# static check on a probe call with dummy images
probe = fn([np.zeros((4, 4, 3), dtype=np.uint8)] * 2)
return isinstance(probe, list) Try / catch
try:
detections = slicer(image)
except ValueError as err:
if 'list[Detections]' in str(err):
raise RuntimeError('callback must accept and return a list when batch_size > 1') from err
raise Prevention
- Write the callback as list-in/list-out from the start so batch_size=1 and >1 both work.
- Add a smoke test that runs the slicer once with the production batch_size in CI.
When it happens
Trigger: Constructing InferenceSlicer with batch_size=4 but a callback of the form def callback(image) -> sv.Detections (single-image signature); the slicer calls it with a list and the raw non-list result hits this check.
Common situations: Upgrading a working single-image pipeline to batching without rewriting the callback; wrapping an ultralytics model.predict call that returns a Results list but converting only the first element.
Related errors
- Callback returned {len(detections_in_slices)} Detections for
- `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/cb189b0f19cb6b99.
Report an issue: GitHub.