sgl-project/sglang · error · ValueError

Kimi image placeholders must map one-to-one to image data: e

Error message

Kimi image placeholders must map one-to-one to image data: expected {expected_image_count}, found {placeholder_count} token(s)

What it means

The Kimi K2.5 processor enforces a one-to-one mapping between image placeholders in the text and image_data entries. count_image_placeholders found a placeholder count different from len(image_data), so it fails before loading.

Source

Thrown at python/sglang/srt/multimodal/processors/kimi_k25.py:561

        # HF processor here would silently bypass Kimi's GPU preprocessing.
        super().__init__(hf_config, server_args, processor, *args, **kwargs)
        self.mm_tokens = mm_tokens

    async def process_mm_data_async(
        self,
        image_data: List[Union[str, bytes, Dict]],
        input_text,
        request_obj,
        *args,
        **kwargs,
    ):
        expected_image_count = len(image_data or [])
        placeholder_count = self.count_image_placeholders(
            input_text, self.mm_tokens.image_token_id
        )
        if placeholder_count is not None:
            if placeholder_count != expected_image_count:
                raise ValueError(
                    "Kimi image placeholders must map one-to-one to image data: "
                    f"expected {expected_image_count}, found {placeholder_count} token(s)"
                )
            base_output = await self.fast_load_mm_data(
                prompt=input_text,
                image_data=image_data,
                multimodal_tokens=self.mm_tokens,
                # fast_load_mm_data, unlike load_mm_data, does not derive
                # input_ids from the prompt; without this the wrapper falls back
                # to re-tokenizing the expanded string.
                input_ids=input_text,
            )
        else:
            base_output = await self.load_mm_data(
                prompt=input_text,
                image_data=image_data,
                multimodal_tokens=self.mm_tokens,
            )

View on GitHub (pinned to 0132848349)

Solutions

  1. Align the number of image placeholder tokens in input_text with len(image_data)
  2. Regenerate the prompt with the official chat template for the current image list
  3. If placeholders are absent by design, send no image_data

Example fix

# before
out = await proc.process_mm_data_async(
    prompt=f"{IMG} compare these",
    image_data=[img1, img2],
)

# after
out = await proc.process_mm_data_async(
    prompt=f"{IMG} {IMG} compare these",
    image_data=[img1, img2],
)
Defensive patterns

Strategy: validation

Validate before calling

n = proc.count_image_placeholders(input_text, proc.mm_tokens.image_token_id)
n_img = len(image_data or [])
assert n is None or n == n_img, f"{n} placeholders vs {n_img} images"

Prevention

When it happens

Trigger: Calling process_mm_data_async with input_text whose image placeholder token count != len(image_data) (count_image_placeholders returned non-None and mismatched).

Common situations: Client sends 3 images but the templated prompt has 2 placeholders (or vice versa), or a prompt with zero placeholders while still passing image_data.

Related errors


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