invoke-ai/InvokeAI · error · ValueError

Latent spatial dims must be even, got {h}x{w}

Error message

Latent spatial dims must be even, got {h}x{w}

What it means

patchify_latents performs a 2x2 patchify ([B,32,H,W] -> [B,128,H/2,W/2]) by reshaping spatial dims, which is only valid when both H and W are even. Odd dimensions would lose pixels or break the view/permute, so the function raises ValueError with the offending dims.

Source

Thrown at invokeai/backend/ernie_image/sampling_utils.py:24

from typing import List

import torch

# Latent channels of the ERNIE-Image VAE (AutoencoderKLFlux2). The transformer's
# `in_channels` is this value times 4 (after a 2x2 patchify).
LATENT_CHANNELS: int = 32

# Total downscale factor between the image and the latent grid. Matches
# `2 ** len(vae.config.block_out_channels)` for AutoencoderKLFlux2.
VAE_SCALE_FACTOR: int = 16


def patchify_latents(latents: torch.Tensor) -> torch.Tensor:
    """2x2 patchify: [B, 32, H, W] -> [B, 128, H/2, W/2]."""
    b, c, h, w = latents.shape
    if h % 2 or w % 2:
        raise ValueError(f"Latent spatial dims must be even, got {h}x{w}")
    latents = latents.view(b, c, h // 2, 2, w // 2, 2)
    latents = latents.permute(0, 1, 3, 5, 2, 4)
    return latents.reshape(b, c * 4, h // 2, w // 2)


def unpatchify_latents(latents: torch.Tensor) -> torch.Tensor:
    """Reverse 2x2 patchify: [B, 128, H/2, W/2] -> [B, 32, H, W]."""
    b, c, h, w = latents.shape
    latents = latents.reshape(b, c // 4, 2, 2, h, w)
    latents = latents.permute(0, 1, 4, 2, 5, 3)
    return latents.reshape(b, c // 4, h * 2, w * 2)


def pad_text(
    text_hiddens: List[torch.Tensor],
    device: torch.device,
    dtype: torch.dtype,
    text_in_dim: int,

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Resize/pad the input image so latents are even (image dimensions multiple of 2*VAE_scale, e.g. multiples of 16 px).
  2. Center-crop the latents down to even H and W before patchifying.
  3. Round width/height choices in the UI/graph to the model's supported multiples.

Example fix

// before
latents = vae.encode(image_501x333)  # -> 63x42? no: 62x41 odd
patchify_latents(latents)  # raises
// after
image = image.resize((512, 512))  # multiples of 16
latents = vae.encode(image)
patchify_latents(latents)
Defensive patterns

Strategy: validation

Validate before calling

b, c, h, w = latents.shape
assert h % 2 == 0 and w % 2 == 0, f"pad/crop latents before patchify: {h}x{w}"

Type guard

def is_patchifiable(latents: torch.Tensor) -> bool:
    return latents.dim() == 4 and latents.shape[-2] % 2 == 0 and latents.shape[-1] % 2 == 0

Try / catch

try:
    patched = patchify_latents(latents)
except ValueError as e:
    if "must be even" in str(e):
        b, c, h, w = latents.shape
        latents = latents[:, :, : h - h % 2, : w - w % 2]
        patched = patchify_latents(latents)
    else:
        raise

Prevention

When it happens

Trigger: Calling patchify_latents on a latent tensor whose height or width is odd — e.g. latent size 33x41 produced by encoding an image whose dimensions don't round to a multiple of the VAE downscale factor.

Common situations: User-supplied images with odd pixel dimensions after VAE encoding (dim/8 rounding); custom resize logic producing non-multiple-of-16 latents; img2img pipelines not padding inputs.

Related errors


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