sgl-project/sglang · error · ValueError
decoder_stage_channels[{stage_idx + 1}] must be {expected},
Error message
decoder_stage_channels[{stage_idx + 1}] must be {expected}, got {stage_channels[stage_idx + 1]}. What it means
The decoder's upsampling stages reduce channels by decoder_upsample_channel_reductions between consecutive stages; stage N+1's channel count must equal stage N's channels divided by that stage's reduction factor. __init__ cross-checks the decoder_stage_channels list against the reductions and raises on any inconsistent pair, catching config errors early instead of inside the first block forward.
Source
Thrown at python/sglang/multimodal_gen/runtime/models/decoders/ltx_2_5_diffusion_decoder.py:661
def __init__(self, config: LTX25DiffusionDecoderConfig) -> None:
super().__init__()
arch = config.arch_config
stage_channels = tuple(arch.decoder_stage_channels)
stage_depths = tuple(arch.decoder_stage_depths)
stage_kernels = tuple(tuple(k) for k in arch.decoder_stage_kernels)
upsample_strides = tuple(tuple(s) for s in arch.decoder_upsample_strides)
reductions = tuple(arch.decoder_upsample_channel_reductions)
if arch.decoder_model_output_type not in ("x0", "v"):
raise ValueError(
"decoder_model_output_type must be 'x0' or 'v', got "
f"{arch.decoder_model_output_type!r}."
)
# An inconsistent pair would only fail deep inside the first block.
for stage_idx, reduction in enumerate(reductions):
expected = stage_channels[stage_idx] // reduction
if stage_channels[stage_idx + 1] != expected:
raise ValueError(
f"decoder_stage_channels[{stage_idx + 1}] must be "
f"{expected}, got {stage_channels[stage_idx + 1]}."
)
self.patch_size = arch.patch_size
self.out_channels = arch.out_channels
self.timestep_scale_multiplier = arch.decoder_timestep_scale_multiplier
self.model_output_type = arch.decoder_model_output_type
self.default_num_inference_steps = arch.decoder_num_inference_steps
self.temporal_compression_ratio = arch.temporal_compression_ratio
self.context_channels = stage_channels[-1]
# Replicated through stages 1-4 and cropped before stage 5, moving the
# border effect past the frames that are kept.
self.trailing_pad_latent_frames = (stage_kernels[0][0] // 2) * 2
self.conv_in = nn.Linear(arch.latent_channels, stage_channels[0], bias=True)
self.det_stages = nn.ModuleList()View on GitHub (pinned to 0132848349)
Solutions
- Recompute the chain: stage_channels[i+1] must equal stage_channels[i] // reductions[i] for every stage; fix the offending entry indicated by stage_idx+1
- Prefer deriving channel lists from a base width and the reduction factors programmatically instead of hand-writing both lists
- Diff your arch config against the shipped LTX-2.5 defaults to spot the edited entry
Example fix
# before arch.decoder_stage_channels = (640, 320, 160) arch.decoder_upsample_channel_reductions = (2, 4) # 320//4=80 != 160 -> error # after arch.decoder_stage_channels = (640, 320, 80) arch.decoder_upsample_channel_reductions = (2, 4)
Defensive patterns
Strategy: validation
Validate before calling
ch = list(arch.decoder_stage_channels)
for i, r in enumerate(arch.decoder_upsample_channel_reductions):
if ch[i+1] != ch[i] // r:
raise ValueError(f"stage {i+1} channels {ch[i+1]} != {ch[i]}//{r}") Type guard
def stages_consistent(channels: tuple[int,...], reductions: tuple[int,...]) -> bool:
return len(channels) == len(reductions) + 1 and all(
channels[i+1] == channels[i] // reductions[i] for i in range(len(reductions))
) Try / catch
try:
decoder = Ltx25DiffusionDecoder(arch)
except ValueError as e:
if "decoder_stage_channels" in str(e):
arch.decoder_stage_channels = derive_from_base(base, reductions)
decoder = Ltx25DiffusionDecoder(arch)
else:
raise Prevention
- Derive stage channels programmatically from a base width and reduction factors instead of hand-editing lists
- Validate the full arch in a config sanity check before model construction
When it happens
Trigger: Building the decoder with a decoder_stage_channels list where any consecutive pair is not exactly related by the corresponding decoder_upsample_channel_reductions factor — e.g. [640, 320, 160] with reductions [2, 4] (320 != 640//2 is fine, but 160 != 320//4 fails).
Common situations: Editing stage widths for a smaller model variant without recomputing reductions; merging configs from different model revisions; typos in the channel or reduction lists.
Related errors
- decoder_model_output_type must be 'x0' or 'v', got {arch.dec
- Invalid {self.vae_scale_factor=}. Must be > 0.
- Invalid {self.patch_size=}. Must be > 0.
- head_dim must be a multiple of 8, got {head_dim}.
- dim {dim} must be divisible by head_dim {head_dim}.
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/896cc4fb8a352ca4.
Report an issue: GitHub.