sgl-project/sglang · error · ValueError
ControlNet down and mid residuals must be provided together.
Error message
ControlNet down and mid residuals must be provided together.
What it means
Raised by the Hunyuan3D SD2.1 UNet forward when exactly one of down_block_additional_residuals and mid_block_additional_residual is provided. ControlNet outputs come as a set of down-block residuals plus one mid-block residual; supplying only one side would misalign the residual additions.
Source
Thrown at python/sglang/multimodal_gen/runtime/models/dits/stable_diffusion.py:833
class_labels: torch.Tensor | None = None,
timestep_cond: torch.Tensor | None = None,
attention_mask: torch.Tensor | None = None,
cross_attention_kwargs: dict[str, Any] | None = None,
added_cond_kwargs: dict[str, torch.Tensor] | None = None,
down_block_additional_residuals: tuple[torch.Tensor, ...] | None = None,
mid_block_additional_residual: torch.Tensor | None = None,
down_intrablock_additional_residuals: tuple[torch.Tensor, ...] | None = None,
encoder_attention_mask: torch.Tensor | None = None,
return_dict: bool = True,
) -> StableDiffusionUNetOutput | tuple[torch.Tensor]:
if timestep_cond is not None or added_cond_kwargs is not None:
raise ValueError("The Hunyuan3D SD2.1 UNet has no added conditioning.")
if down_intrablock_additional_residuals is not None:
raise ValueError("T2I adapter residuals are not supported by Hunyuan3D.")
if (down_block_additional_residuals is None) != (
mid_block_additional_residual is None
):
raise ValueError(
"ControlNet down and mid residuals must be provided together."
)
attention_mask = self._attention_bias(attention_mask, sample.dtype)
encoder_attention_mask = self._attention_bias(
encoder_attention_mask, sample.dtype
)
if self.config.center_input_sample:
sample = 2 * sample - 1.0
time_embedding = self._time_embedding(sample, timestep)
if self.class_embedding is not None:
if class_labels is None:
raise ValueError("class_labels are required by this UNet.")
time_embedding = time_embedding + self.class_embedding(class_labels).to(
sample.dtype
)
View on GitHub (pinned to 0132848349)
Solutions
- Pass both down_block_additional_residuals and mid_block_additional_residual (or neither)
- Check the ControlNet forward returns and feed [:-1] to down and [-1] to mid
Example fix
# before unet(x, t, encoder_hidden_states=ctx, down_block_additional_residuals=res[:-1]) # after unet(x, t, encoder_hidden_states=ctx, down_block_additional_residuals=res[:-1], mid_block_additional_residual=res[-1])
Defensive patterns
Strategy: type-guard
Validate before calling
assert (down_res is None) == (mid_res is None), "ControlNet residuals must come in pairs"
Type guard
def controlnet_residuals_paired(down, mid) -> bool:
return (down is None) == (mid is None) Prevention
- Feed res[:-1] to down and res[-1] to mid in one expression
When it happens
Trigger: Passing down_block_additional_residuals without mid_block_additional_residual, or vice versa.
Common situations: Running a ControlNet whose down/residual list was sliced incorrectly, or forgetting to forward controlnet_res[0] and controlnet_res[-1] together.
Related errors
- Hunyuan3D Paint does not use extra UNet conditioning.
- Hunyuan3D Paint does not use added conditioning.
- The native SD2 UNet currently supports only the Hunyuan3D fo
- Hunyuan3D SD2.1 UNet requires four channel stages.
- Hunyuan3D SD2.1 UNet requires two ResNet layers and one tran
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/164a221e0a18aabf.
Report an issue: GitHub.