{"record":{"id":"c917faaf7a60268d","repo":"sgl-project/sglang","slug":"expected-len-image-token-counts-image-placehold-c917fa","errorCode":null,"errorMessage":"Expected {len(image_token_counts)} image placeholder token(s), found {placeholder_count}.","messagePattern":"Expected (.+?) image placeholder token\\(s\\), found (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/multimodal/processors/kimi_k3.py","lineNumber":98,"sourceCode":"    tokenizer,\n) -> torch.Tensor:\n    \"\"\"Expand K3 image placeholders into the checkpoint's media contract.\n\n    K3 requires each image feature span to be enclosed by its original uploaded\n    dimensions.  The chat template deliberately emits one ``media_pad`` per\n    image; after decode, insert the surrounding control tokens and expand that\n    one placeholder to the NaViT feature count.\n    \"\"\"\n    if len(image_token_counts) != len(image_sizes):\n        raise ValueError(\"Expected one original size for each K3 image.\")\n\n    if isinstance(input_ids, torch.Tensor):\n        input_ids = input_ids.detach().flatten().cpu().numpy()\n    input_ids = np.asarray(input_ids, dtype=np.int64)\n\n    placeholder_count = np.count_nonzero(input_ids == image_token_id)\n    if placeholder_count != len(image_token_counts):\n        raise ValueError(\n            f\"Expected {len(image_token_counts)} image placeholder token(s), \"\n            f\"found {placeholder_count}.\"\n        )\n\n    output = []\n    image_index = 0\n    for token_id in input_ids:\n        if token_id != image_token_id:\n            output.append(int(token_id))\n            continue\n\n        width, height = image_sizes[image_index]\n        output.extend(\n            _encode_k3_special_tokens(\n                tokenizer,\n                f\"<|media_begin|>image {width}x{height}<|media_content|>\",\n            )\n        )","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/multimodal/processors/kimi_k3.py#L80-L116","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nids = tokenizer(prompt_with_2_placeholders).input_ids\nexpand(ids, image_token_counts=[c1, c2, c3])  # 3 counts, 2 placeholders\n# after\nassert ids.count(image_token_id) == len(image_token_counts)\nexpand(ids, image_token_counts=[c1, c2])","handlingStrategy":"validation","validationCode":"import numpy as np\ndef check_ids(ids, image_token_id, counts):\n    n = int(np.count_nonzero(np.asarray(ids) == image_token_id))\n    assert n == len(counts), f\"{n} placeholders vs {len(counts)} images\"","typeGuard":null,"tryCatchPattern":"try:\n    expand(ids, counts)\nexcept ValueError as e:\n    if \"placeholder\" in str(e): re_tokenize_prompt_and_retry()\n    else: raise","preventionTips":["Always tokenize and expand in the same code path","Never truncate input_ids between tokenization and expansion"],"tags":["multimodal","kimi-k3","placeholder-mismatch","validation"],"backgroundTag":"multimodal-placeholder-count-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}