roboflow/supervision · error · ValueError
Border sizes must be non-negative
Error message
Border sizes must be non-negative
What it means
`cv2.copyMakeBorder` fallback at src/supervision/_cv2/_image.py:47 requires all four border sizes (top, bottom, left, right) to be >= 0. Negative borders would mean cropping, which the function's output-shape construction `(H + top + bottom, W + left + right, ...)` cannot represent, so they are rejected before array allocation.
Source
Thrown at src/supervision/_cv2/_image.py:47
else:
raise ValueError(f"Unsupported flip code: {flip_code}")
return np.ascontiguousarray(np.flip(image, axis=axes))
def _copy_make_border(
image: npt.NDArray[Any],
top: int,
bottom: int,
left: int,
right: int,
border_type: int,
value: int | float | Sequence[int | float] = 0,
) -> npt.NDArray[Any]:
"""Add a constant border around an image."""
if border_type != _BORDER_CONSTANT:
raise ValueError("Only BORDER_CONSTANT is supported by the fallback")
if min(top, bottom, left, right) < 0:
raise ValueError("Border sizes must be non-negative")
height, width = image.shape[:2]
shape = (height + top + bottom, width + left + right, *image.shape[2:])
# OpenCV's Scalar(v) fills only channel 0 and zero-pads the rest for
# multichannel images — a bare scalar is treated the same as a
# length-1 sequence, not broadcast to every channel.
sequence_value = value if isinstance(value, Sequence) else (value,)
values = np.asarray(sequence_value, dtype=image.dtype).reshape(-1)
if image.ndim == 2:
fill_value: Any = values[0] if values.size else 0
else:
fill = np.zeros(image.shape[2], dtype=image.dtype)
fill[: min(values.size, image.shape[2])] = values[: image.shape[2]]
fill_value = fill.reshape((1, 1, -1))
result = np.full(shape, fill_value, dtype=image.dtype)
result[top : top + height, left : left + width] = imageView on GitHub (pinned to 7f254d9784)
Solutions
- Clamp computed pads to zero: `top = max(0, (target_h - h) // 2)`
- If negative pad means crop, do the crop explicitly instead: `img[-top:h+bottom, -left:w+right]`
- Validate pad configuration at load time and reject negative values early
Example fix
// before pad_top = (target_h - h) // 2 # negative when h > target_h out = cv2.copyMakeBorder(img, pad_top, pad_top, 0, 0, cv2.BORDER_CONSTANT) // after pad_top = max(0, (target_h - h) // 2) out = cv2.copyMakeBorder(img, pad_top, pad_top, 0, 0, cv2.BORDER_CONSTANT)
Defensive patterns
Strategy: validation
Validate before calling
def clamp_pads(top: int, bottom: int, left: int, right: int) -> tuple[int, int, int, int]:
"""copyMakeBorder requires non-negative border sizes."""
pads = tuple(max(0, int(p)) for p in (top, bottom, left, right))
if min(top, bottom, left, right) < 0:
# negative pad usually means the image already exceeds the target — crop instead
pass
return pads # type: ignore[return-value] Type guard
def is_non_negative_pad(*sizes: int) -> bool:
"""All four border sizes must be >= 0."""
return all(isinstance(s, int) and s >= 0 for s in sizes) Prevention
- Clamp letterbox pad math with max(0, ...) at the computation site
- Treat negative computed pads as a signal to crop, not pad
When it happens
Trigger: Passing a negative border width, usually from arithmetic on computed pad sizes: e.g. `pad = (target - size) // 2` going negative when the image is already larger than the target, then forwarded to copyMakeBorder.
Common situations: Letterboxing/resizing helpers that compute symmetric pads without clamping; config-driven pad values where a minus sign typo survives into runtime.
Related errors
- At least one channel is required
- Only BORDER_CONSTANT is supported by the fallback
- module {__name__} has no attribute {name}
- Edge indices must use the 1-based convention and be within t
- sigma must contain at least one value
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/80331785e1b3baa3.
Report an issue: GitHub.