lllyasviel/Fooocus · 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

In the ControlNet/latent-diffusion UNet builder (cldm.py), num_res_blocks may be an int (same depth at every resolution level) or a per-level list whose length must equal len(channel_mult). A mismatched list raises ValueError at model construction. This validation precedes the asserts on disable_self_attentions/num_attention_blocks, which also index by level.

Source

Thrown at ldm_patched/controlnet/cldm.py:88

        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.dims = dims
        self.image_size = image_size
        self.in_channels = in_channels
        self.model_channels = model_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)
            assert all(map(lambda i: self.num_res_blocks[i] >= num_attention_blocks[i], range(len(num_attention_blocks))))

        transformer_depth = transformer_depth[:]

        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 ae05379cc9)

Solutions

  1. If depth is uniform, use the int form: num_res_blocks: 2.
  2. Otherwise make len(num_res_blocks) == len(channel_mult) — for SD1.x that is 4 entries, e.g. [2,2,2,2] with channel_mult [1,2,4,4].
  3. Diff the failing config against the reference controlnet sd15 config shipped in the repo and align both fields.
  4. Sanity-check any sibling per-level lists (disable_self_attentions, num_attention_blocks) against the same length.

Example fix

# before
channel_mult=[1, 2, 4, 4, 5]
num_res_blocks=[2, 2, 2, 2]  # ValueError: len mismatch

# after
channel_mult=[1, 2, 4, 4, 5]
num_res_blocks=[2, 2, 2, 2, 2]  # lengths match
Defensive patterns

Strategy: validation

Validate before calling

if isinstance(num_res_blocks, int):
    num_res_blocks = [num_res_blocks] * len(channel_mult)
else:
    num_res_blocks = list(num_res_blocks)
    if len(num_res_blocks) != len(channel_mult):
        raise ValueError(f'len(num_res_blocks)={len(num_res_blocks)} != len(channel_mult)={len(channel_mult)}')

Type guard

def is_valid_res_blocks(nrb, channel_mult) -> bool:
    return isinstance(nrb, int) or (isinstance(nrb, (list, tuple)) and len(nrb) == len(channel_mult))

Try / catch

try:
    model = ControlNet(model_cfg)
except ValueError as e:
    if 'num_res_blocks' in str(e):
        raise ValueError('Config error: num_res_blocks must be int or per-level list matching channel_mult') from e
    raise

Prevention

When it happens

Trigger: Loading a SD1.5/SD2.x ControlNet config where num_res_blocks=[2,2,2,2] but channel_mult=[1,2,4,4,4] (5 levels), or vice versa; hand-edited config YAMLs that change one field without the other.

Common situations: Diffusion-model configs from different model families (SD1.x uses 4-level channel_mult, SD2.1/SDXL differ); copying a config from another repo (e.g. k-diffusion or original CompVis) with per-level block counts; custom training configs.

Related errors


AI-assisted analysis of lllyasviel/Fooocus@ae05379cc9 (2026-08-15). Data as JSON: /api/errors/123a4b6d198affa1. Report an issue: GitHub.