invoke-ai/InvokeAI · error · ValueError

Unexpected cond image shape: {tuple(rgb_bchw_01.shape)} (exp

Error message

Unexpected cond image shape: {tuple(rgb_bchw_01.shape)} (expected B,3,H,W)

What it means

prepare_cond_image converts an RGB conditioning image shaped (B,3,H,W) in [0,1] into the tensor ControlNet-LLLite expects, resizing to the latent-derived target. It raises ValueError when the tensor is not 4-D or its channel dimension is not 3 — i.e. it was passed grayscale, batched-with-alpha, or wrongly permuted data.

Source

Thrown at invokeai/backend/anima/control_net_lllite.py:80

def target_cond_hw(latent_h: int, latent_w: int, patch_spatial: int = 2) -> tuple[int, int]:
    """Return the (H, W) the cond image / mask must be resized to.

    The LLLite ``conditioning1`` trunk has total conv stride 16, so the cond
    image must be sized to ``latent_HW * 8`` in input pixel space (= token_HW
    * 16 after DiT patchify with patch_spatial=2). The DiT internally pads the
    latent up to a multiple of ``patch_spatial`` before patchify, so the same
    rounding is mirrored here — otherwise odd latent dims yield a token-count
    mismatch that silently bypasses every LLLite module.
    """
    padded_h = ((latent_h + patch_spatial - 1) // patch_spatial) * patch_spatial
    padded_w = ((latent_w + patch_spatial - 1) // patch_spatial) * patch_spatial
    return padded_h * 8, padded_w * 8


def prepare_cond_image(rgb_bchw_01: torch.Tensor, latent_h: int, latent_w: int, patch_spatial: int = 2) -> torch.Tensor:
    """RGB image (B, 3, H, W) in [0, 1] -> (1, 3, H_t, W_t) in [-1, 1]."""
    if rgb_bchw_01.ndim != 4 or rgb_bchw_01.shape[1] != 3:
        raise ValueError(f"Unexpected cond image shape: {tuple(rgb_bchw_01.shape)} (expected B,3,H,W)")
    img = rgb_bchw_01[:1]
    target_h, target_w = target_cond_hw(latent_h, latent_w, patch_spatial)
    if img.shape[-2] != target_h or img.shape[-1] != target_w:
        img = F.interpolate(img, size=(target_h, target_w), mode="bicubic", align_corners=False)
        img = img.clamp(0.0, 1.0)
    return img * 2.0 - 1.0


def prepare_mask(mask_b1hw_01: torch.Tensor, latent_h: int, latent_w: int, patch_spatial: int = 2) -> torch.Tensor:
    """Mask (B, 1, H, W) or (B, H, W) in [0, 1] -> (1, 1, H_t, W_t) in {0.0, 1.0}.

    1 = inpaint area, 0 = keep. The caller is responsible for the ``*2-1``
    rescale before concat with RGB (see :func:`build_inpaint_cond_image`).
    """
    if mask_b1hw_01.ndim == 3:
        m = mask_b1hw_01.unsqueeze(1)
    elif mask_b1hw_01.ndim == 4 and mask_b1hw_01.shape[1] == 1:
        m = mask_b1hw_01

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Ensure input is a float tensor with shape (B,3,H,W) and values in [0,1].
  2. If shape is (H,W,3) or (3,H,W), add/permute: img.permute(2,0,1).unsqueeze(0).
  3. Convert grayscale to RGB with .repeat(1,3,1,1) and drop alpha channels.
  4. Validate with a guard before calling (see validationCode).

Example fix

# before
cond = prepare_cond_image(image_np.transpose(2, 0, 1), latent_h, latent_w)
# after
import torch
img = torch.from_numpy(image_np).permute(2, 0, 1).unsqueeze(0).float() / 255.0
assert img.shape[1] == 3, img.shape
cond = prepare_cond_image(img, latent_h, latent_w)
Defensive patterns

Strategy: validation

Validate before calling

import torch
def validate_cond_image(img: torch.Tensor) -> None:
    if not isinstance(img, torch.Tensor):
        raise TypeError("cond image must be a torch.Tensor")
    if img.ndim != 4 or img.shape[1] != 3:
        raise ValueError(f"expected (B,3,H,W), got {tuple(img.shape)}")
    if img.min() < 0.0 or img.max() > 1.0:
        raise ValueError("cond image values must be in [0,1]")

Type guard

def is_rgb_bchw(t) -> bool:
    import torch
    return isinstance(t, torch.Tensor) and t.ndim == 4 and t.shape[1] == 3

Try / catch

try:
    cond = prepare_cond_image(img, latent_h, latent_w)
except ValueError as e:
    raise ValueError(f"bad conditioning image: {e}; provide float (B,3,H,W) in [0,1]") from e

Prevention

When it happens

Trigger: Calling prepare_cond_image (directly or via _build_lllite_cond_image) with a tensor of shape (3,H,W) (missing batch dim), (B,1,H,W) grayscale, (B,H,W,3) NHWC layout, or ndim != 4.

Common situations: Loading images via PIL/cv2 and forgetting to permute HWC->CHW, passing a mask instead of an RGB image, passing a batch of 1 without the leading dimension, or using a 4-channel RGBA image.

Understand the failure class

Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.

Related errors


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