invoke-ai/InvokeAI · error

Cannot achieve the target of num_channels={num_channels}.

Error message

Cannot achieve the target of num_channels={num_channels}.

What it means

prepare_control_image slices the resized control-image tensor down to exactly `num_channels`. If the tensor has fewer channels than requested (or num_channels is <= 0), the target channel count is unreachable and this ValueError is raised instead of silently producing a malformed control input.

Source

Thrown at invokeai/app/util/controlnet_utils.py:426

        nimage = np.array(nimage).astype(np.float32) / 255.0
        nimage = nimage.transpose(0, 3, 1, 2)
        timage = torch.from_numpy(nimage)

    # use fancy lvmin controlnet resizing
    elif resize_mode == "just_resize" or resize_mode == "crop_resize" or resize_mode == "fill_resize":
        nimage = np.array(image)
        timage, nimage = np_img_resize(
            np_img=nimage,
            resize_mode=resize_mode,
            h=height,
            w=width,
            device=torch.device(device),
        )
    else:
        raise ValueError(f"Unsupported resize_mode: '{resize_mode}'.")

    if timage.shape[1] < num_channels or num_channels <= 0:
        raise ValueError(f"Cannot achieve the target of num_channels={num_channels}.")
    timage = timage[:, :num_channels, :, :]

    timage = timage.to(device=device, dtype=dtype)
    cfg_injection = control_mode == "more_control" or control_mode == "unbalanced"
    if do_classifier_free_guidance and not cfg_injection:
        timage = torch.cat([timage] * 2)
    return timage

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Check the control image's channel count and convert it to RGB (3 channels) before passing it in
  2. Verify the ControlNet/T2I-Adapter model config has a correct positive channels field; re-import or fix the model record
  3. Ensure the resize_mode branch you took actually produces a tensor with >= num_channels channels
  4. Pass an explicit valid num_channels when calling prep_control_data instead of deriving it from a bad config

Example fix

// before
img = Image.open('mask.png')  # mode 'L', 1 channel
control_data = prep_control_data(..., control_image=img, ...)  # ValueError
// after
img = Image.open('mask.png').convert('RGB')
control_data = prep_control_data(..., control_image=img, ...)
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np
from PIL import Image

def ensure_channels_ok(image, num_channels):
    if num_channels is None or num_channels <= 0:
        raise ValueError(f"num_channels must be positive, got {num_channels}")
    arr = np.asarray(Image.open(image) if isinstance(image, str) else image)
    if arr.ndim == 2:
        ch = 1
    elif arr.shape[-1] in (1, 2, 3, 4):
        ch = arr.shape[-1]
    else:
        ch = 3
    if ch < num_channels:
        raise ValueError(f"image has {ch} channels; need {num_channels}")

Type guard

def has_enough_channels(t, num_channels):
    return num_channels > 0 and t.dim() >= 3 and t.shape[1] >= num_channels

Try / catch

try:
    control_data = prep_control_data(..., control_image=img, ...)
except ValueError as e:
    if 'num_channels' in str(e):
        img = img.convert('RGB')
        control_data = prep_control_data(..., control_image=img, ...)
    else:
        raise

Prevention

When it happens

Trigger: Calling prep_control_data / run_t2i_adapters / prepare_controlnet_cond with a control image whose effective channel count after resizing is less than the model's required channels (e.g. 1-channel or 4-channel image against 3 channels required is fine, but 3-channel against 4 required fails), or passing num_channels <= 0 via a misconfigured ControlNet/T2I-Adapter model field.

Common situations: Using a grayscale single-channel control image with a model expecting more channels; a ControlNet model record whose target channels value is 0 or negative due to a bad/legacy config; feeding an alpha-only PNG loaded with 2 channels.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/0013c626d83b40b7. Report an issue: GitHub.