invoke-ai/InvokeAI · error · ValueError
expected {LATENT_DIM} packed channels, got {channels}
Error message
expected {LATENT_DIM} packed channels, got {channels} What it means
unpatchify_and_denormalize expects the packed latent tensor to have exactly LATENT_DIM channels; any other channel count cannot be unpatchified back into the 32-channel autoencoder latent space.
Source
Thrown at invokeai/backend/ideogram4/sampling_utils.py:120
"""
batch_size = z.shape[0]
z = z.reshape(batch_size, grid_h, grid_w, LATENT_DIM)
return z.permute(0, 3, 1, 2).contiguous()
def unpatchify_and_denormalize(
packed: torch.Tensor,
latent_shift: torch.Tensor,
latent_scale: torch.Tensor,
) -> torch.Tensor:
"""Convert a packed latent ``(1, LATENT_DIM, grid_h, grid_w)`` to a VAE latent ``(1, 32, H/8, W/8)``.
Applies the per-channel latent denormalization (``z * scale + shift``) in the
packed space, then unpatchifies, exactly as ``Ideogram4Pipeline._decode`` does.
"""
batch_size, channels, grid_h, grid_w = packed.shape
if channels != LATENT_DIM:
raise ValueError(f"expected {LATENT_DIM} packed channels, got {channels}")
# (B, grid_h, grid_w, LATENT_DIM)
z = packed.permute(0, 2, 3, 1)
z = z * latent_scale.to(z.device, z.dtype) + latent_shift.to(z.device, z.dtype)
ae_channels = LATENT_DIM // (PATCH_SIZE * PATCH_SIZE) # 32
z = z.reshape(batch_size, grid_h, grid_w, PATCH_SIZE, PATCH_SIZE, ae_channels)
z = z.permute(0, 5, 1, 3, 2, 4).contiguous()
z = z.reshape(batch_size, ae_channels, grid_h * PATCH_SIZE, grid_w * PATCH_SIZE)
return z
View on GitHub (pinned to 0b6a024f2f)
Solutions
- Ensure the tensor passed in is the LATENT_DIM-channel packed tensor produced by patchify/pipeline denoise steps
- Check tensor.permute/reshape so channels are in dim 1
- If starting from a VAE latent, patchify it (pack LATENT_DIM = ae_channels * PATCH_SIZE^2) first
Example fix
// before unpatchify_and_denormalize(vae_latent, scale, shift) # 32 channels // after packed = patchify(vae_latent) # -> (B, LATENT_DIM, gh, gw) unpatchify_and_denormalize(packed, scale, shift)
Defensive patterns
Strategy: type-guard
Validate before calling
assert packed.ndim == 4, f"expected (B,C,gh,gw), got {packed.shape}"
assert packed.shape[1] == LATENT_DIM, f"need {LATENT_DIM} channels, got {packed.shape[1]}" Type guard
def is_packed_latent(t: torch.Tensor) -> bool:
return t.ndim == 4 and t.shape[1] == LATENT_DIM Try / catch
try:
image = unpatchify_and_denormalize(packed, scale, shift)
except ValueError as e:
if "packed channels" in str(e):
packed = patchify(packed) # or fix permute
image = unpatchify_and_denormalize(packed, scale, shift)
else:
raise Prevention
- Only feed tensors produced by the pipeline's patchify step into unpatchify
- Check channel count in callbacks before decoding
- Keep a single helper for pack/unpack to avoid shape drift
When it happens
Trigger: Passing a raw VAE latent (e.g. 16 or 32 channels) or a mis-patched tensor to unpatchify_and_denormalize from step_callback or invoke instead of the LATENT_DIM-channel packed diffusion tensor.
Common situations: Wiring the decoded image callback to the wrong tensor, using latents from another model's VAE, forgetting the patchify step, transposing shape incorrectly so channels dimension is wrong.
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
- Wan reference condition must be a 5D tensor; got shape {tupl
- Wan latents-to-video expects a 5D latent tensor [B, C, T, H,
- Input img and txt tensors must have 3 dimensions.
- Input img and txt tensors must have 3 dimensions.
- color_tensor must be a 3xHxW tensor
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/d15a7f05e158f894.
Report an issue: GitHub.