Comfy-Org/ComfyUI · error · ValueError

provide num_res_blocks either as an int (globally constant)

Error message

provide num_res_blocks either as an int (globally constant) or as a list/tuple (per-level) with the same length as channel_mult

What it means

Raised by UNetModel (openaimodel.py) when num_res_blocks is given as a list/tuple whose length differs from channel_mult. The constructor accepts either one int (applied to all levels) or a per-level sequence that must align 1:1 with channel_mult; a mismatch means the config is ambiguous and construction aborts.

Source

Thrown at comfy/ldm/modules/diffusionmodules/openaimodel.py:476

        if num_heads_upsample == -1:
            num_heads_upsample = num_heads

        if num_heads == -1:
            assert num_head_channels != -1, 'Either num_heads or num_head_channels has to be set'

        if num_head_channels == -1:
            assert num_heads != -1, 'Either num_heads or num_head_channels has to be set'

        self.in_channels = in_channels
        self.model_channels = model_channels
        self.out_channels = out_channels

        if isinstance(num_res_blocks, int):
            self.num_res_blocks = len(channel_mult) * [num_res_blocks]
        else:
            if len(num_res_blocks) != len(channel_mult):
                raise ValueError("provide num_res_blocks either as an int (globally constant) or "
                                 "as a list/tuple (per-level) with the same length as channel_mult")
            self.num_res_blocks = num_res_blocks

        if disable_self_attentions is not None:
            # should be a list of booleans, indicating whether to disable self-attention in TransformerBlocks or not
            assert len(disable_self_attentions) == len(channel_mult)
        if num_attention_blocks is not None:
            assert len(num_attention_blocks) == len(self.num_res_blocks)

        transformer_depth = transformer_depth[:]
        transformer_depth_output = transformer_depth_output[:]

        self.dropout = dropout
        self.channel_mult = channel_mult
        self.conv_resample = conv_resample
        self.num_classes = num_classes
        self.use_checkpoint = use_checkpoint
        self.dtype = dtype

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Make len(num_res_blocks) == len(channel_mult), or pass a single int
  2. Diff the config against the original checkpoint's config to find which level list drifted
  3. If you added a channel_mult level, add the matching num_res_blocks entry

Example fix

# before
UNetModel(channel_mult=(1, 2, 4, 8), num_res_blocks=[2, 2, 2])
# after
UNetModel(channel_mult=(1, 2, 4, 8), num_res_blocks=[2, 2, 2, 2])
Defensive patterns

Strategy: validation

Validate before calling

if isinstance(num_res_blocks, (list, tuple)) and len(num_res_blocks) != len(channel_mult):
    raise ValueError(f'num_res_blocks len {len(num_res_blocks)} != channel_mult len {len(channel_mult)}')
model = UNetModel(num_res_blocks=num_res_blocks, channel_mult=channel_mult)

Type guard

def num_res_blocks_valid(nrb, channel_mult) -> bool:
    return isinstance(nrb, int) or len(nrb) == len(channel_mult)

Prevention

When it happens

Trigger: Passing num_res_blocks=[2,2,2,2] with channel_mult=[1,2,4,6] (length 4 vs 3), or a truncated/extended per-level list from an edited config.

Common situations: Hand-tuning SD-style UNet configs for depth; porting configs between model variants (base vs depth variants list different channel_mult lengths); diffusers-to-ComfyUI config conversions dropping or adding a level.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/8a47938c1e3471f9. Report an issue: GitHub.