sgl-project/sglang · error · ValueError
mm_content_hashes has {len(image_hashes)} entries for {image
Error message
mm_content_hashes has {len(image_hashes)} entries for {image_index} images What it means
Raised while building mm_data on the receiver when the request's mm_content_hashes list length does not match the number of image entries actually collected from image_data. Hashes are indexed positionally per image (videos/audio are skipped), so any mismatch means the client's hash list is inconsistent with the image payload and cache lookups would be wrong.
Source
Thrown at python/sglang/srt/disaggregation/encoder/receiver.py:2384
mm_item.content_hash
if isinstance(mm_item, ImageData)
else (
mm_item.get("content_hash")
if isinstance(mm_item, dict)
else None
)
)
explicit_hash = (
image_hashes[image_index]
if image_hashes is not None
and image_index < len(image_hashes)
else None
)
entry["content_hash"] = explicit_hash or inline_hash
image_index += 1
mm_data.append(entry)
if image_hashes is not None and image_index != len(image_hashes):
raise ValueError(
f"mm_content_hashes has {len(image_hashes)} entries for "
f"{image_index} images"
)
return mm_data
class MMReceiverHTTP(MMReceiverBase):
def __init__(
self,
server_args: ServerArgs,
dtype: Optional[torch.dtype] = None,
hf_config: Optional[PretrainedConfig] = None,
pp_rank: Optional[int] = None,
tp_rank: Optional[int] = None,
tp_group: Optional[GroupCoordinator] = None,
scheduler: Optional["Scheduler"] = None,
encode_urls: Optional[List[str]] = None,
):View on GitHub (pinned to 0132848349)
Solutions
- Make mm_content_hashes contain exactly one entry per non-None image (URL-bearing) item in image_data, in the same order.
- Do not include hashes for video/audio items; only images are hashed positionally here.
- Drop mm_content_hashes (send None) if per-image content hashing is not needed.
- Filter out None/empty image entries before building the hash list.
Example fix
# before req.mm_content_hashes = [h_img, h_video] req.image_data = [img] # after req.mm_content_hashes = [h_img] req.image_data = [img]
Defensive patterns
Strategy: validation
Validate before calling
def count_hashable_images(req) -> int:
n = 0
for item in req.image_data or []:
url = item.url if hasattr(item, "url") else (item or {}).get("url") if isinstance(item, dict) else item
if item is not None and url is not None:
n += 1
return n
if req.mm_content_hashes is not None:
assert len(req.mm_content_hashes) == count_hashable_images(req) Try / catch
try:
mm_data = build_mm_data(request_obj)
except ValueError as e:
if "mm_content_hashes" in str(e):
request_obj.mm_content_hashes = None # degrade to no content hashing
mm_data = build_mm_data(request_obj) Prevention
- Build mm_content_hashes with a list comprehension over the same filtered image list sent in image_data.
- Never include video/audio hashes in mm_content_hashes.
- Omit mm_content_hashes entirely (None) when content-hash caching is not required.
When it happens
Trigger: Sending a request with mm_content_hashes=[h1, h2] but only one non-None image in image_data; or images whose URL is None (skipped) while hashes were still provided for them; also passing hashes when image_data is empty.
Common situations: Client code that precomputes hashes for all multimodal items including videos; None-valued ImageData placeholders; a bug in hash-list construction after filtering images; version drift between client and server on how many hash entries are expected.
Related errors
- Invalid modality: {modality}
- content hash mismatch for media_data[{index}]: expected {cal
- cos/sin shape does not cover image tokens and head_dim
- Unsupported image type: {type(image)}
- QwenImageEditPlus expects either one shared condition image
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/a1581915d09e74be.
Report an issue: GitHub.