sgl-project/sglang · error · ValueError
predict_num_frames supports a single prediction only, got sh
Error message
predict_num_frames supports a single prediction only, got shape {tuple(predicted_seconds.shape)}. One frame count cannot serve prompts with different natural durations. What it means
predict_num_frames converts a predicted duration (seconds) into a single frame count, which only makes sense for exactly one sample. If the model was given a batch (or a multi-prompt tensor), one scalar frame count cannot represent different natural durations, so it errors when predicted_seconds.numel() != 1.
Source
Thrown at python/sglang/multimodal_gen/runtime/models/adapter/ltx_2_duration_head.py:136
def predict_num_frames(
self,
video_tokens: torch.Tensor | None = None,
audio_tokens: torch.Tensor | None = None,
*,
frame_rate: float,
temporal_compression_ratio: int,
min_seconds: float = 1.0,
max_seconds: float = 20.0,
) -> int:
"""Predict a frame count on the VAE's causal temporal grid.
Clamp first, then snap: a clamped count is not necessarily grid-aligned,
so snapping first would give a different answer.
"""
predicted_seconds = self(video_tokens, audio_tokens)
if predicted_seconds.numel() != 1:
raise ValueError(
"predict_num_frames supports a single prediction only, got shape "
f"{tuple(predicted_seconds.shape)}. One frame count cannot serve "
"prompts with different natural durations."
)
seconds = predicted_seconds.item()
# Floor at 1 so the grid arithmetic cannot go negative.
min_frames = max(1, round(min_seconds * frame_rate))
max_frames = round(max_seconds * frame_rate)
clamped_frames = max(min_frames, min(round(seconds * frame_rate), max_frames))
num_frames = (
(clamped_frames - 1) // temporal_compression_ratio
) * temporal_compression_ratio + 1
if num_frames < min_frames:
# Flooring undershot the lower bound; take the next grid point up.
snapped_up = num_frames + temporal_compression_ratioView on GitHub (pinned to 0132848349)
Solutions
- Call predict_num_frames per sample: index/slice the token tensors to batch size 1 before calling
- Restructure the loop to iterate over batch items and collect per-item frame counts
- If you truly want one count for all prompts, pick per-sample prediction first and then aggregate deliberately
Example fix
# before
num_frames = head.predict_num_frames(video_tokens, audio_tokens) # batched
# after
num_frames = [
head.predict_num_frames(video_tokens[i:i+1], audio_tokens[i:i+1] if audio_tokens is not None else None)
for i in range(video_tokens.shape[0])
] Defensive patterns
Strategy: validation
Validate before calling
if video_tokens.shape[0] > 1:
raise ValueError("call predict_num_frames per sample, batched input unsupported")
num_frames = head.predict_num_frames(video_tokens, audio_tokens) Type guard
def is_single_sample(t: torch.Tensor) -> bool:
return t.dim() >= 1 and t.shape[0] == 1 Try / catch
try:
n = head.predict_num_frames(v, a)
except ValueError as e:
if "single prediction only" in str(e):
n = [head.predict_num_frames(v[i:i+1], None if a is None else a[i:i+1]) for i in range(v.shape[0])]
else:
raise Prevention
- Treat predict_num_frames as a per-sample API in batched code paths
- Add a batch-size-1 assertion in shared helpers that wrap this call
When it happens
Trigger: Calling `head.predict_num_frames(video_tokens=..., audio_tokens=...)` with a batched tensor of shape (B, ...) where B > 1, since forward returns shape (B,) and numel() > 1.
Common situations: Scaling a single-sample generation script to batch inference; mixing per-prompt loops with vectorized batching; tests that accidentally pass a batch dimension of 2.
Related errors
- Expected x.shape[-1] to be even for split rotary, got {last}
- The `hidden_states` sequence length {hidden_states.shape[1]}
- LTX2DurationHead requires at least one of video_tokens / aud
- head_dim must be a multiple of 8, got {head_dim}.
- Z-Image expects one caption embedding per image, got {len(al
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/fa8314a96d9def13.
Report an issue: GitHub.