roboflow/supervision · error · ValueError

Each RLE payload must be a mapping.

Error message

Each RLE payload must be a mapping.

What it means

Raised by CompactMask.from_coco_rle when an element of the rles sequence is not a Mapping (dict-like). Each RLE payload must expose 'size' and 'counts' keys, which requires mapping access; lists, tuples, strings, or None are rejected with this error before any key lookup.

Source

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

            raise ValueError(
                "xyxy must have shape (N, 4), where N matches the number of RLEs."
            )

        if len(rles) == 0:
            return cls(
                [],
                np.empty((0, 2), dtype=np.int32),
                np.empty((0, 2), dtype=np.int32),
                (img_h, img_w),
            )

        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"])

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Normalize each payload to a dict with the two keys: {'size': [h, w], 'counts': counts}.
  2. Filter out None/empty segmentation entries before building the list.
  3. If you have parallel arrays of sizes and counts, zip them into dicts before the call.

Example fix

# before
rles = [ann["segmentation"]["counts"] for ann in anns]

# after
rles = [{"size": ann["segmentation"]["size"],
         "counts": ann["segmentation"]["counts"]} for ann in anns]
Defensive patterns

Strategy: type-guard

Validate before calling

from collections.abc import Mapping
assert all(isinstance(r, Mapping) and {"size", "counts"} <= r.keys() for r in rles), "bad RLE payload"

Type guard

from collections.abc import Mapping

def is_coco_rle_payload(obj) -> bool:
    return isinstance(obj, Mapping) and "size" in obj and "counts" in obj

Try / catch

try:
    cm = sv.CompactMask.from_coco_rle(rles, xyxy, image_shape=shape)
except ValueError as e:
    if "must be a mapping" in str(e):
        rles = [r if isinstance(r, dict) else {"size": s, "counts": r} for r, s in zip(rles, sizes)]
    else:
        raise

Prevention

When it happens

Trigger: Passing rles = [[4, 4], ...] (positional lists), rles = [None], rles = ['01b...'] (bare compressed strings), or a numpy structured array instead of [{'size': ..., 'counts': ...}, ...].

Common situations: Grabbing ann['segmentation']['counts'] strings from COCO JSON and zipping them into lists instead of rebuilding dicts; passing pycocotools RLE objects (which are dicts and fine) mixed with raw strings; None placeholders for missing masks.

Related errors


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