sgl-project/sglang · error · ValueError

{name} placeholder/data mismatch: {placeholder_count} placeh

Error message

{name} placeholder/data mismatch: {placeholder_count} placeholders vs {data_count} {name}s

What it means

Raised by _validate_placeholder_counts when the number of multimodal placeholder tokens embedded in the prompt text doesn't equal the number of supplied data items per modality (image, video, audio counted separately). It guards the text-template vs payload consistency of the request.

Source

Thrown at python/sglang/srt/multimodal/processors/mimo_v2.py:1521

        counts = {
            Modality.IMAGE: 0,
            Modality.VIDEO: 0,
            Modality.AUDIO: 0,
        }
        for text_part in text_parts:
            if multimodal_tokens_pattern.match(text_part):
                modality = self.mm_tokens.get_modality_of_token(text_part)
                if modality in counts:
                    counts[modality] += 1

        for modality, name, data_count in (
            (Modality.IMAGE, "image", image_count),
            (Modality.VIDEO, "video", video_count),
            (Modality.AUDIO, "audio", audio_count),
        ):
            placeholder_count = counts[modality]
            if placeholder_count != data_count:
                raise ValueError(
                    f"{name} placeholder/data mismatch: "
                    f"{placeholder_count} placeholders vs {data_count} {name}s"
                )

    def __init__(self, hf_config, server_args, _processor, *args, **kwargs):
        super().__init__(hf_config, server_args, _processor, *args, **kwargs)
        self.vision_config = Qwen2_5_VLVisionConfig.from_dict(hf_config.vision_config)

        patch_size = self.vision_config.patch_size
        spatial_merge_size = getattr(self.vision_config, "spatial_merge_size", 2)
        unit_size = patch_size * spatial_merge_size
        self.image_factor = unit_size

        rope_type = "rope"
        rope_scaling = getattr(hf_config, "rope_scaling", None)
        if rope_scaling:
            if (
                rope_scaling.get("type", None) == "default"

View on GitHub (pinned to 0132848349)

Solutions

  1. Make placeholders and data lists generated from the same source: text = template.format per item, images=[...] of equal length
  2. Count tokens per modality before submit and assert equality client-side
  3. For video-with-audio, account for audio placeholders exactly as the model template expects

Example fix

# before
text = '<|image|><|image|><|image|> describe'
images = [img1, img2]           # 3 placeholders vs 2 images → ValueError
# after
text = '<|image|>' * len(images) + ' describe'
images = [img1, img2]
Defensive patterns

Strategy: validation

Validate before calling

import re
from collections import Counter
def check(prompt, images=0, videos=0, audios=0):
    c = Counter(re.findall(r'<\|image\|>', prompt))['<|image|>'] if images else 0
    # count each modality's placeholder token and compare:
    assert prompt.count(IMAGE_TOKEN) == images, f'{prompt.count(IMAGE_TOKEN)} vs {images}'
    assert prompt.count(VIDEO_TOKEN) == videos
    assert prompt.count(AUDIO_TOKEN) == audios

check(text, images=len(images), videos=len(videos), audios=len(audios))

Try / catch

try:
    out = await epd.process_mm_data_async(text, images=images, videos=videos, audios=audios)
except ValueError as e:
    if 'placeholder/data mismatch' in str(e):
        return error_response(400, str(e) + '; regenerate prompt from attachments')
    raise

Prevention

When it happens

Trigger: Sending a prompt with, say, 3 <|image|> placeholders but only 2 image entries in images=[...]; or 1 video placeholder with 2 videos; likewise for audio. Any per-modality count mismatch between text template and data list triggers it.

Common situations: Templating bugs where the placeholder loop count drifts from the attachments list; client code appending images without adding tokens (or vice versa); copy-pasting prompts with leftover placeholders; audio placeholders missing when sending video-with-audio.

Related errors


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