sgl-project/sglang · error · ValueError

Image aspect ratio must be smaller than 200

Error message

Image aspect ratio must be smaller than 200

What it means

Raised by the Dots3 vision tower's image preprocessing when the input image's aspect ratio (max dimension / min dimension) exceeds 200. The processor enforces this bound because the smart-resize logic rounds each side up to a factor multiple, and an extremely elongated image would explode into an enormous number of vision tokens / patches. It is a hard validation of user-supplied image geometry.

Source

Thrown at python/sglang/srt/models/dots3_common/dots_omni_towers.py:132

    def _resized_size(
        self,
        width: int,
        height: int,
        min_pixels: int,
        max_pixels: int,
        target_height=None,
        target_width=None,
    ):
        height = target_height or height
        width = target_width or width
        factor = self.patch_size * self.merge_size
        if min(height, width) < factor // 4:
            raise ValueError(
                f"Image height/width must be at least {factor // 4}, "
                f"got {height}x{width}"
            )
        if max(height, width) / min(height, width) > 200:
            raise ValueError("Image aspect ratio must be smaller than 200")
        resized_h = max(factor, self._round_by_factor(height, factor))
        resized_w = max(factor, self._round_by_factor(width, factor))
        if resized_h * resized_w > max_pixels:
            beta = math.sqrt(height * width / max_pixels)
            resized_h = max(factor, self._floor_by_factor(height / beta, factor))
            resized_w = max(factor, self._floor_by_factor(width / beta, factor))
        elif resized_h * resized_w < min_pixels:
            beta = math.sqrt(min_pixels / (height * width))
            resized_h = self._ceil_by_factor(height * beta, factor)
            resized_w = self._ceil_by_factor(width * beta, factor)
            if resized_h * resized_w > max_pixels:
                beta = math.sqrt(resized_h * resized_w / max_pixels)
                resized_h = max(factor, self._floor_by_factor(resized_h / beta, factor))
                resized_w = max(factor, self._floor_by_factor(resized_w / beta, factor))
        return resized_h, resized_w

    def _process_image(self, image, detail="auto"):
        if not isinstance(image, Image.Image):

View on GitHub (pinned to 0132848349)

Solutions

  1. Pre-crop or resize the image so its aspect ratio is below 200 before sending it to the model
  2. Verify the image is not corrupted or zero-width/height (decode it with PIL and check image.size)
  3. If long documents are the goal, split the image into tiles/pages each within the ratio limit
  4. Add a client-side guard: compute max(h,w)/min(h,w) and reject/downscale before calling process_images

Example fix

# before
image = Image.open('banner_20000x50.png')
processor.process_images([image])

# after
h, w = image.size
if max(h, w) / min(h, w) > 200:
    raise ValueError('crop or resize: aspect ratio too large')
processor.process_images([image])
Defensive patterns

Strategy: validation

Validate before calling

from PIL import Image

def check_aspect(img: Image.Image, limit: float = 200.0) -> bool:
    w, h = img.size
    return max(w, h) / min(w, h) <= limit

Try / catch

try:
    processor.process_images([img])
except ValueError as e:
    if 'aspect ratio' in str(e):
        img = crop_or_tile_to_ratio(img)
    else:
        raise

Prevention

When it happens

Trigger: Calling process_images (which calls _process_image -> _resized_size) with an image whose max(height,width)/min(height,width) > 200, e.g. a 20000x50 pixel strip. Any min side >= factor//4 check passing earlier does not protect against this; only the ratio matters.

Common situations: Feeding scanned banners, long receipts, thin lines, or corrupted/mis-decoded images into a Dots3 multimodal request; images produced by cropping pipelines that keep one dimension tiny; accidentally swapping coordinates.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/76073fa414ca5bad. Report an issue: GitHub.