sgl-project/sglang · error · ValueError
QwenImage text conditioning mask has shape {tuple(mask.shape
Error message
QwenImage text conditioning mask has shape {tuple(mask.shape)}, expected {(batch_size, text_seq_len)}. What it means
For text conditioning, QwenImage expects a per-encoder boolean mask of shape (batch_size, text_seq_len) matching the current batch. If the stored prompt (or negative prompt) embeds mask has a different shape — stale cache, mismatched encoder index, or reshaped batch — this ValueError is thrown in _prepare_encoder_hidden_states_mask.
Source
Thrown at python/sglang/multimodal_gen/configs/pipeline_configs/qwen_image.py:438
dim], so we pass a [batch, text_seq_len] boolean mask to keep attention
on real text tokens and ignore padding.
If every request uses the full padded length, no mask is needed and this
returns None. Otherwise, prefer the embedding-aligned mask stored by the
text encoding stage. If that is unavailable, rebuild the same mask from
`txt_seq_lens`: position j is valid for row i when
`j < txt_seq_lens[i]`.
"""
if all(seq_len == text_seq_len for seq_len in txt_seq_lens):
return None
masks_by_encoder = (
batch.negative_prompt_embeds_mask if negative else batch.prompt_embeds_mask
)
if masks_by_encoder is not None and encoder_index < len(masks_by_encoder):
mask = masks_by_encoder[encoder_index]
if mask.shape != (batch_size, text_seq_len):
raise ValueError(
"QwenImage text conditioning mask has shape "
f"{tuple(mask.shape)}, expected {(batch_size, text_seq_len)}."
)
return mask
# TODO: cache positions by (device, text_seq_len) if this allocation shows up hot.
positions = torch.arange(text_seq_len, device=batch.prompt_embeds[0].device)
seq_lens = torch.tensor(
txt_seq_lens,
device=batch.prompt_embeds[0].device,
dtype=torch.long,
)
return positions.unsqueeze(0) < seq_lens.unsqueeze(1)
def prepare_pos_cond_kwargs(self, batch, device, rotary_emb, dtype):
return self._prepare_cond_kwargs(
batch, batch.prompt_embeds, rotary_emb, device, dtype, negative=False
)View on GitHub (pinned to 0132848349)
Solutions
- Recompute text embeddings/masks for the current batch instead of reusing cached ones
- Ensure prompt and negative prompt go through the same tokenizer/padding so masks share (batch_size, text_seq_len)
- If caching, key the cache by (batch_size, text_seq_len) and invalidate on mismatch
Example fix
# before mask = cached_masks[encoder_index] # from earlier request # after mask = encode_text(batch) # recompute for current batch_size / text_seq_len assert mask.prompt_embeds_mask[0].shape == (batch_size, text_seq_len)
Defensive patterns
Strategy: validation
Validate before calling
expected = (batch_size, text_seq_len)
for enc_idx in range(num_encoders):
m = masks[enc_idx]
assert m is None or tuple(m.shape) == expected, f"mask {enc_idx}: {tuple(m.shape)} != {expected}" Try / catch
try:
mask = pipe._prepare_encoder_hidden_states_mask(batch, encoder_index, negative, batch_size, text_seq_len)
except ValueError:
batch.prompt_embeds_mask = None # drop stale cache
batch = pipe.encode_text(batch) # recompute
mask = pipe._prepare_encoder_hidden_states_mask(batch, encoder_index, negative, batch_size, text_seq_len) Prevention
- Never mix cached embed masks across batches with different sizes/lengths
- Key mask caches by (batch_size, text_seq_len)
- Apply identical padding to positive and negative prompt encodes
When it happens
Trigger: Batch size or text sequence length changed between embedding computation and denoising (e.g. CFG negative branch with different prompt lengths); reusing cached prompt_embeds_mask from a previous request with a different batch/seq len; encoder_index pointing at a mask computed with different padding.
Common situations: Mixing cached text embeddings across requests with different batch sizes or prompt token counts; padding/tokenization inconsistencies between prompt and negative prompt paths; dynamic batching that changes batch_size after masks were computed.
Related errors
- Qwen-Image-Layered generated latent shapes must match, got {
- {tensor_name}{context_clause} with shape {tensor.shape} cann
- Block sparse tensors{context} must have shapes (B, H, M) and
- Block sparse tensors{context} {dim_name} dim must be {tgt} o
- Block sparse tensors{context} must share the same m-block di
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/d5363d96557600ab.
Report an issue: GitHub.