sgl-project/sglang · error · ValueError
prompt has {num_placeholders} image placeholder token(s) but
Error message
prompt has {num_placeholders} image placeholder token(s) but {len(counts)} image(s) were provided What it means
_expand_input_ids verifies that the number of placeholder token ids in the already-tokenized prompt exactly equals the number of expansion 'counts' (per-image expanded token counts). A mismatch means the prompt text and the media list disagree, so retokenize-avoidance expansion cannot proceed safely.
Source
Thrown at python/sglang/srt/multimodal/processors/base_processor.py:1631
counts: List[int],
placeholder_token_id: Optional[int],
) -> List[int]:
"""Rebuild final input_ids for a pre-tokenized (list[int]) prompt.
Keep the user's ORIGINAL tokens verbatim and expand the i-th image
placeholder into ``counts[i]`` copies of ``placeholder_token_id``. The HF
processor's re-tokenization is discarded, so non-media tokens cannot
drift.
"""
if placeholder_token_id is None:
raise ValueError("placeholder_token_id is not set for this processor")
num_placeholders = sum(
1 for token_id in original_ids if token_id == placeholder_token_id
)
if num_placeholders != len(counts):
raise ValueError(
f"prompt has {num_placeholders} image placeholder token(s) but "
f"{len(counts)} image(s) were provided"
)
rebuilt: List[int] = []
next_image_idx = 0
for token_id in original_ids:
if token_id == placeholder_token_id:
rebuilt.extend([placeholder_token_id] * counts[next_image_idx])
next_image_idx += 1
else:
rebuilt.append(token_id)
return rebuilt
def process_and_combine_mm_data(
self,
base_output: BaseMultiModalProcessorOutput,
mm_tokens: MultimodalSpecialTokens,View on GitHub (pinned to 0132848349)
Solutions
- Regenerate the prompt with the model's chat template so placeholders match len(images) exactly
- Ensure the tokenized ids correspond to the same prompt/media pairing used to compute counts
- Avoid manually inserting or deleting placeholder tokens in the token ids
Example fix
// before
input_ids = tokenizer('<image> <image>') # 2 placeholders
counts = [c for c in per_img] # 3 images
// after
input_ids = tokenizer('<image>' * len(images))
counts = [c for c in per_img] # len == len(images) == placeholders Defensive patterns
Strategy: validation
Validate before calling
num_ph = sum(1 for t in input_ids if t == placeholder_token_id)
assert num_ph == len(counts), f'{num_ph} placeholders vs {len(counts)} images' Prevention
- Always build the prompt via the chat template with the same media list used for counts
- Never splice extra placeholder tokens into pre-tokenized ids
When it happens
Trigger: Calling process_and_combine_mm_data where the tokenized prompt contains N placeholder tokens but the resolved per-image counts list has a different length — e.g. prompt with 2 <image> tags but 3 images provided, or custom text embedding extra placeholder tokens.
Common situations: Chat templates that add/remove placeholder tokens conditionally; offline tokenized prompts reused with different image counts; duplicated placeholder tokens from string interpolation.
Related errors
- processor image placeholder count mismatch: processor={proce
- InklingMultimodalProcessor: {n_img_ph} image placeholder tok
- Unsupported image type: {type(image)}
- When using multiple prompts with multiple input images, prov
- {key}.position_ids is required
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/3d15c37e92e962a3.
Report an issue: GitHub.