roboflow/supervision · error · ValueError

new_image_shape must contain positive dimensions

Error message

new_image_shape must contain positive dimensions

What it means

Raised by CompactMask.with_offset when new_image_shape contains a zero or negative height or width. The method re-embeds each mask crop at a new offset on a canvas of the given size, so the canvas must be positively sized before bounds checks run.

Source

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

            Crops are clipped to stay inside ``new_image_shape``; masks fully
            outside are represented as ``1x1`` all-False crops.

        Examples:
            ```pycon
            >>> import numpy as np
            >>> from supervision.detection.compact_mask import CompactMask
            >>> masks = np.zeros((1, 20, 20), dtype=bool)
            >>> xyxy = np.array([[5, 5, 15, 15]], dtype=np.float32)
            >>> cm = CompactMask.from_dense(masks, xyxy, image_shape=(20, 20))
            >>> cm2 = cm.with_offset(100, 200, new_image_shape=(400, 400))
            >>> cm2.offsets[0].tolist()
            [105, 205]

            ```
        """
        new_h, new_w = new_image_shape
        if new_h <= 0 or new_w <= 0:
            raise ValueError("new_image_shape must contain positive dimensions")

        num_masks = len(self)
        if num_masks == 0:
            return CompactMask(
                [],
                np.empty((0, 2), dtype=np.int32),
                np.empty((0, 2), dtype=np.int32),
                new_image_shape,
            )

        # Vectorised bounds check: compute every new [x1,y1,x2,y2] at once.
        # For the common case (InferenceSlicer tiles that fit fully inside the
        # new canvas) this catches the "no clipping needed" path in O(N) numpy
        # without touching any RLE data.
        new_offsets: npt.NDArray[np.int32] = self._offsets + np.array(
            [dx, dy], dtype=np.int32
        )
        x1s = new_offsets[:, 0]

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Compute the destination canvas from the original image: new_image_shape = img.shape[:2], not from tile arithmetic.
  2. Clamp/validate computed shapes: assert h > 0 and w > 0 before calling with_offset.
  3. Skip fully out-of-canvas tiles rather than constructing a zero-size canvas for them.

Example fix

# before
cm2 = cm.with_offset(x, y, new_image_shape=(max(0, W - x - w), H))

# after
cm2 = cm.with_offset(x, y, new_image_shape=img.shape[:2])
Defensive patterns

Strategy: validation

Validate before calling

new_h, new_w = new_image_shape
assert new_h > 0 and new_w > 0, f"bad new_image_shape {(new_h, new_w)}"
cm2 = cm.with_offset(dx, dy, new_image_shape=(new_h, new_w))

Prevention

When it happens

Trigger: Calling cm.with_offset(dx, dy, new_image_shape=(0, 400)) or with negative dims; computing new_image_shape from an arithmetic expression (old_shape - margins) that can reach 0 or below for edge-case tiles.

Common situations: Stitching InferenceSlicer tiles back together with a shape computed as min/max of tile coordinates that degenerates; passing (w, h) where one entry was 0; off-by-one making a dimension negative near image borders.

Related errors


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