sgl-project/sglang · error · ValueError

The number of placeholders does not match the number of repl

Error message

The number of placeholders does not match the number of replacements.

What it means

Step3-VL's replace_placeholder splits the prompt text on the image placeholder token and requires the count of placeholder occurrences to exactly equal the number of replacement strings (one per image patch/window). A mismatch means the number of image tags in the text does not match the number of processed image segments produced by the processor.

Source

Thrown at python/sglang/srt/multimodal/processors/step3_vl.py:433

        num_images: int,
        num_patches: int,
        patch_new_line_idx: Optional[list[bool]],
    ) -> tuple[str, list[int]]:
        if num_patches > 0:
            patch_repl, patch_repl_ids = self._get_patch_repl(
                num_patches, patch_new_line_idx
            )
        else:
            patch_repl = ""
            patch_repl_ids = []
        image_repl, image_repl_ids = self._get_image_repl(num_images)
        return patch_repl + image_repl, patch_repl_ids + image_repl_ids

    def replace_placeholder(self, text: str, placeholder: str, repls: list[str]) -> str:
        parts = text.split(placeholder)

        if len(parts) - 1 != len(repls):
            raise ValueError(
                "The number of placeholders does not match the number of replacements."  # noqa: E501
            )

        result = [parts[0]]
        for i, repl in enumerate(repls):
            result.append(repl)
            result.append(parts[i + 1])

        return "".join(result)

    def __call__(
        self,
        text: Optional[Union[str, list[str]]] = None,
        images: Optional[Union[Image.Image, list[Image.Image]]] = None,
        return_tensors: Optional[Union[str, TensorType]] = None,
        *args,
        **kwargs,
    ) -> BatchFeature:

View on GitHub (pinned to 0132848349)

Solutions

  1. Make the number of image tags in the text exactly match len(image_inputs)
  2. Check for placeholder typos/duplicates against the processor's expected placeholder constant
  3. Verify all image URLs/base64 payloads actually resolved before the request

Example fix

# before
text = '<img><img>'  # 2 tags
images = [img1]      # 1 image
# after
text = '<img>'
images = [img1]
Defensive patterns

Strategy: validation

Validate before calling

n_tags = text.count(placeholder)
assert n_tags == len(repls), f'{n_tags} tags vs {len(repls)} images'

Try / catch

try:
    processor(...)
except ValueError as e:
    if 'placeholders' in str(e):
        raise HTTPBadRequest('image tag count must match attached images')

Prevention

When it happens

Trigger: Prompt contains N image placeholder tags but M != N images were supplied (or vice versa); duplicate placeholder in one tag; placeholder string typo so split counts 0 occurrences while repls is non-empty.

Common situations: User chat message embeds two image tags but attaches one image; frontend inserts extra placeholder tokens; multi-image requests where one image failed download and was silently dropped, desynchronizing counts.

Related errors


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