roboflow/supervision · error · ValueError

RLE size must be [height, width].

Error message

RLE size must be [height, width].

What it means

Raised by CompactMask.from_coco_rle when rle['size'] cannot be unpacked into two integers — unpacking raised TypeError (wrong length or non-iterable) or ValueError (non-numeric values). The message restates the expected COCO convention: size must be a two-element [height, width] sequence.

Source

Thrown at src/supervision/detection/compact_mask.py:821

            )

        crop_rles: list[npt.NDArray[np.int32]] = []
        crop_shapes_list: list[tuple[int, int]] = []
        offsets_list: list[tuple[int, int]] = []

        for mask_idx, rle in enumerate(rles):
            if not isinstance(rle, Mapping):
                raise ValueError("Each RLE payload must be a mapping.")
            if "size" not in rle or "counts" not in rle:
                raise ValueError("Each RLE payload must contain 'size' and 'counts'.")

            try:
                # COCO standard: size=[height, width] (h,w order per pycocotools spec)
                rle_h, rle_w = rle["size"]
                rle_h = int(rle_h)
                rle_w = int(rle_w)
            except (TypeError, ValueError) as exc:
                raise ValueError("RLE size must be [height, width].") from exc

            if (rle_h, rle_w) != (img_h, img_w):
                raise ValueError(
                    f"RLE size {(rle_h, rle_w)} must match image_shape "
                    f"{(img_h, img_w)}."
                )

            counts = _coco_rle_counts_to_array(rle["counts"])
            if int(np.sum(counts, dtype=np.int64)) != img_h * img_w:
                raise ValueError(
                    "The sum of COCO RLE counts must match the image area."
                )

            x1, y1, x2, y2 = xyxy_arr[mask_idx]
            x1i, y1i, x2i, y2i = int(x1), int(y1), int(x2), int(y2)
            x1c = max(0, min(x1i, img_w - 1))
            y1c = max(0, min(y1i, img_h - 1))

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Ensure size is exactly two integers in [height, width] order: [720, 1280].
  2. If size arrives as a string, parse it first: tuple(map(int, s.split('x'))).
  3. Check for swapped size/counts keys in the payload dict.

Example fix

# before
rles = [{"size": [4, 4, 3], "counts": [0, 2, 2, 2, 10]}]

# after
rles = [{"size": [4, 4], "counts": [0, 2, 2, 2, 10]}]
Defensive patterns

Strategy: type-guard

Validate before calling

for r in rles:
    size = r["size"]
    assert len(size) == 2, f"size must have 2 elements, got {size!r}"
    h, w = int(size[0]), int(size[1])

Type guard

def is_valid_rle_size(size) -> bool:
    return (
        isinstance(size, (list, tuple))
        and len(size) == 2
        and all(isinstance(v, (int, float)) and not isinstance(v, bool) for v in size)
    )

Prevention

When it happens

Trigger: Passing size=[640] (one element), size=[h, w, c] (three elements), size='640x480' (a string), size=None, or size containing floats/strings like '720' that int() rejects in the tuple unpack.

Common situations: Building RLE dicts from custom metadata with wrong tuple arity; storing size as a string in a database and passing it raw; accidentally assigning 'size': counts and 'counts': size (swapped fields).

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/16efb8807438b96a. Report an issue: GitHub.