sgl-project/sglang · error · ValueError
Expected {len(image_token_counts)} image placeholder token(s
Error message
Expected {len(image_token_counts)} image placeholder token(s), found {placeholder_count}. What it means
Raised by KimiK3ProcessorHelper._expand_k3_image_prompt_token_ids when the number of image placeholder tokens found in the already-tokenized input_ids does not equal the number of image token counts supplied. The library throws it because each <|IMAGE_TOKEN|> placeholder in the prompt must be expanded to per-image token sequences, so a mismatch would silently corrupt alignment.
Source
Thrown at python/sglang/srt/multimodal/processors/kimi_k3.py:98
tokenizer,
) -> torch.Tensor:
"""Expand K3 image placeholders into the checkpoint's media contract.
K3 requires each image feature span to be enclosed by its original uploaded
dimensions. The chat template deliberately emits one ``media_pad`` per
image; after decode, insert the surrounding control tokens and expand that
one placeholder to the NaViT feature count.
"""
if len(image_token_counts) != len(image_sizes):
raise ValueError("Expected one original size for each K3 image.")
if isinstance(input_ids, torch.Tensor):
input_ids = input_ids.detach().flatten().cpu().numpy()
input_ids = np.asarray(input_ids, dtype=np.int64)
placeholder_count = np.count_nonzero(input_ids == image_token_id)
if placeholder_count != len(image_token_counts):
raise ValueError(
f"Expected {len(image_token_counts)} image placeholder token(s), "
f"found {placeholder_count}."
)
output = []
image_index = 0
for token_id in input_ids:
if token_id != image_token_id:
output.append(int(token_id))
continue
width, height = image_sizes[image_index]
output.extend(
_encode_k3_special_tokens(
tokenizer,
f"<|media_begin|>image {width}x{height}<|media_content|>",
)
)View on GitHub (pinned to 0132848349)
Solutions
- Verify the prompt string contains exactly one image token per supplied image before calling the API
- Check that input_ids were not truncated or sliced after tokenization (e.g. by context-length trimming)
- Regenerate artifacts so len(artifacts) matches the number of placeholders in the prompt
Example fix
# before ids = tokenizer(prompt_with_2_placeholders).input_ids expand(ids, image_token_counts=[c1, c2, c3]) # 3 counts, 2 placeholders # after assert ids.count(image_token_id) == len(image_token_counts) expand(ids, image_token_counts=[c1, c2])
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np
def check_ids(ids, image_token_id, counts):
n = int(np.count_nonzero(np.asarray(ids) == image_token_id))
assert n == len(counts), f"{n} placeholders vs {len(counts)} images" Try / catch
try:
expand(ids, counts)
except ValueError as e:
if "placeholder" in str(e): re_tokenize_prompt_and_retry()
else: raise Prevention
- Always tokenize and expand in the same code path
- Never truncate input_ids between tokenization and expansion
When it happens
Trigger: Calling compose_request/get_mm_data with input_ids whose count of image_token_id occurrences differs from len(image_token_counts); typically after the tokenizer rendered fewer/more image placeholders than images provided, or input_ids were truncated/pre-trimmed.
Common situations: Prompt template omits or duplicates the image placeholder string per image; multimodal prefill chunking or truncation removes placeholder tokens; a cached/stale artifact list length differs from the re-tokenized prompt.
Related errors
- Kimi-K3 encoder mode supports image input only
- Expected {len(image_token_counts)} image placeholder(s), fou
- Z-Image text embeddings must have shape [seq, dim] or [batch
- f"Unsupported patch_size type: {type(patch_size)}"
- f"Expected camera embedding shape [B, C, F, H, W], got {tupl
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/c917faaf7a60268d.
Report an issue: GitHub.