sgl-project/sglang · error · ValueError
content hash mismatch for media_data[{index}]: expected {cal
Error message
content hash mismatch for media_data[{index}]: expected {caller_hash}, got {snapshot.content_digest} What it means
After asynchronously loading a media snapshot, prepare_media_artifacts compares the snapshot's content_digest with the caller-supplied hash for that index. A mismatch means the underlying media content changed (or the hash was computed over different bytes), so the cached artifact would be stale/incorrect and the run is aborted.
Source
Thrown at python/sglang/srt/multimodal/media_artifacts/base.py:336
allow_featureless=allow_featureless,
)
if artifact is not None:
artifacts[index] = artifact
continue
load_indices.append(index)
# 2. read cache: build artifact key from media snapshot then try reading cache
snapshot_futures = {
index: self.io_executor.submit(
self.snapshot_media_source, media_data[index], modality
)
for index in load_indices
}
for index, future in snapshot_futures.items():
snapshot = await asyncio.wrap_future(future)
caller_hash = content_hashes[index]
if caller_hash is not None and caller_hash != snapshot.content_digest:
raise ValueError(
f"content hash mismatch for media_data[{index}]: "
f"expected {caller_hash}, got {snapshot.content_digest}"
)
snapshots[index] = snapshot
key = self._artifact_key(
snapshot.content_digest, media_data[index], modality=modality
)
keys[index] = key
artifacts[index] = self._get_cached_artifact(
key,
snapshot.content_digest,
modality,
allow_featureless=featureless_hit_mask[index],
)
# 3. deduplicate misses before decode
first_index_by_key: dict[str, int] = {}
previous_metadata: dict[str, MediaArtifact] = {}View on GitHub (pinned to 0132848349)
Solutions
- Recompute the content hash from the exact bytes being loaded and pass the fresh value
- If the media is legitimately updated, treat it as a new item: new hash, new cache entry
- Verify both sides use the same digest function (parse_content_hash's scheme) and same byte payload (no re-encoding)
Example fix
// before hashes = [old_hash_for_url] # url content changed since await prepare_media_artifacts(media, content_hashes=hashes, ...) // after hashes = [sha256(fetch_bytes(url)).hexdigest() for url in media] await prepare_media_artifacts(media, content_hashes=hashes, ...)
Defensive patterns
Strategy: try-catch
Validate before calling
digest = sha256(load_bytes(item)).hexdigest() # pass digest as the content hash so it matches the snapshot by construction
Try / catch
try:
await prepare_media_artifacts(media, content_hashes=hashes, ...)
except ValueError as e:
if "content hash mismatch" in str(e):
hashes = [compute_hash(m) for m in media] # refresh and retry once
await prepare_media_artifacts(media, content_hashes=hashes, ...)
else:
raise Prevention
- Compute hashes from the exact bytes served, at request time
- Use immutable/content-addressed URLs for media assets
When it happens
Trigger: Supplying mm_content_hashes[i] that doesn't equal the digest of the actually loaded media_data[i] — e.g. a URL whose content was updated, a mutated local file, or a hash computed with a different algorithm/normalization.
Common situations: Mutable object-store URLs behind a CDN; hashing the prompt text instead of image bytes; using a stale hash cached from a previous version of the asset; cross-process hash algorithm drift (e.g. blake2 vs sha256).
Related errors
- mm_content_hashes has {len(image_hashes)} entries for {image
- mm_content_hashes has {len(content_hashes)} entries for {med
- 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/6ae55ddfa485b44b.
Report an issue: GitHub.