sgl-project/sglang · error · ValueError
caption_valid_mask must have one row per Z-Image caption
Error message
caption_valid_mask must have one row per Z-Image caption
What it means
Raised by ZImage.patchify_and_embed when an optional caption_valid_mask is provided whose first dimension does not equal len(all_cap_feats). The mask must contain one row (one per-caption validity vector) per caption embedding.
Source
Thrown at python/sglang/multimodal_gen/runtime/models/dits/zimage.py:979
caption_valid_mask: torch.Tensor | None = None,
):
"""Patchify images and pad image/caption tokens to batch targets.
Each image is [C, F, H, W] and has one [L, D] caption. Returned tensors
are stacked as [B, S, D], while valid lengths keep track of real tokens
before learned pad tokens are restored. `image_seq_len_target`, when
set, is the SP-local padded image-token target.
"""
if len(all_image) != len(all_cap_feats):
raise ValueError(
f"Z-Image expects one caption embedding per image, got {len(all_image)} images and {len(all_cap_feats)} captions"
)
if not all_image:
raise ValueError("Z-Image batch must contain at least one image latent")
if caption_valid_mask is not None and caption_valid_mask.shape[0] != len(
all_cap_feats
):
raise ValueError("caption_valid_mask must have one row per Z-Image caption")
pH = pW = patch_size
pF = f_patch_size
all_image_out = []
all_image_size = []
all_cap_feats_out = []
all_image_valid_lens = []
all_cap_valid_lens = []
all_cap_valid_masks = []
all_image_attn_lens = []
all_cap_attn_lens = []
image_records = []
cap_seq_len_target = max(
self._ceil_to_multiple(cap_feat.size(0), SEQ_MULTI_OF)
for cap_feat in all_cap_feats
)
View on GitHub (pinned to 0132848349)
Solutions
- Compute caption_valid_mask after filtering, from the same list used for all_cap_feats
- Add an assert caption_valid_mask.shape[0] == len(all_cap_feats) in your batching code
- Pass caption_valid_mask=None if you don't need per-caption validity
Example fix
# before mask = build_mask(all_caps_before_filter) all_cap_feats = [c for c, ok in zip(all_caps_before_filter, oks) if ok] # after all_cap_feats = [c for c, ok in zip(all_caps_before_filter, oks) if ok] mask = build_mask(all_cap_feats)
Defensive patterns
Strategy: validation
Validate before calling
if caption_valid_mask is not None:
assert caption_valid_mask.shape[0] == len(all_cap_feats) Type guard
def mask_matches_captions(mask: torch.Tensor | None, n_caps: int) -> bool:
return mask is None or mask.shape[0] == n_caps Prevention
- Derive mask from the final filtered caption list, never the pre-filter batch
When it happens
Trigger: Passing caption_valid_mask with shape [B_total, L] while all_cap_feats was filtered down to fewer captions after the mask was built.
Common situations: Building the mask from the pre-filter batch but filtering caption embeddings afterwards; off-by-one errors in batch slicing.
Related errors
- Z-Image expects one caption embedding per image, got {len(al
- Krea-2 sequence parallelism does not support ragged/padded m
- QwenImage text conditioning mask has shape {tuple(mask.shape
- Z-Image text embeddings must have shape [seq, dim] or [batch
- Unable to infer Z-Image caption length for rotary embeddings
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/07672ce4e6d7fca5.
Report an issue: GitHub.