sgl-project/sglang · error · ValueError

mm_content_hashes has {len(content_hashes)} entries for {med

Error message

mm_content_hashes has {len(content_hashes)} entries for {media_count} {modality.name.lower()} items

What it means

prepare_media_artifacts requires the optional mm_content_hashes list to be exactly as long as media_data; a length mismatch means the caller's per-item content hashes cannot be aligned with the media items, so the artifact cache cannot be keyed safely.

Source

Thrown at python/sglang/srt/multimodal/media_artifacts/base.py:285

        """Try resolving one preprocess-cache artifact for each processor input.

        Each media input is looked up independently, and results preserve the
        input order. A cache hit returns the stored artifact (the cache item).
        A miss snapshots and decodes the raw input, runs
        ``prepare_artifact_batch``, stores its cache-safe artifact, and returns
        the prepared artifact to the current request. Duplicate and concurrent
        misses share the same preprocessing work.

        This stage is prompt-independent. It does not create prompt tokens,
        offsets, or ``MultimodalDataItem`` objects; the model processor uses the
        returned artifacts to compose those request-specific values afterward.
        """
        modality = self._resolve_artifact_modality(modality)
        media_count = len(media_data)
        if content_hashes is None:
            content_hashes = [None] * media_count
        if len(content_hashes) != media_count:
            raise ValueError(
                f"mm_content_hashes has {len(content_hashes)} entries for "
                f"{media_count} {modality.name.lower()} items"
            )
        content_hashes = [parse_content_hash(value) for value in content_hashes]

        if featureless_hit_mask is None:
            featureless_hit_mask = [False] * media_count
        if len(featureless_hit_mask) != media_count:
            raise ValueError("featureless_hit_mask must align with media_data")

        # keep per-input state aligned for duplicates and partial hits
        artifacts: list[Optional[MediaArtifact]] = [None] * media_count
        snapshots: list[Optional[MediaSnapshot]] = [None] * media_count
        keys: list[Optional[str]] = [None] * media_count

        # 1. fast path: resolve trusted provided hash hits without reading media
        # e.g., an image could be submitted with a provided hash:
        # "image_url": {

View on GitHub (pinned to 0132848349)

Solutions

  1. Regenerate content_hashes with one entry per item in the current media_data list (in the same order)
  2. If you don't have hashes, pass content_hashes=None instead of a partial list
  3. Log len(media_data) and len(content_hashes) upstream to find where they diverge

Example fix

// before
hashes = [h for h, m in zip(prev_hashes, media) if m in new_set]  # shorter than media
await prepare_media_artifacts(media, content_hashes=hashes, ...)
// after
hashes = [compute_hash(m) for m in media]
await prepare_media_artifacts(media, content_hashes=hashes, ...)
Defensive patterns

Strategy: validation

Validate before calling

assert content_hashes is None or len(content_hashes) == len(media_data), (len(content_hashes), len(media_data))

Prevention

When it happens

Trigger: Calling prepare_media_artifacts (via process_mm_data_async) with content_hashes shorter/longer than media_data — e.g. hashing only new items while resending the full media list, or vice versa.

Common situations: Incremental prefetch flows that compute hashes for a subset of images; EPD/speculative decoding paths where the hash list is built per-request but media_data is per-batch; races where media list is mutated between hash computation and the call.

Related errors


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