invoke-ai/InvokeAI · error · ValueError

height and width must be divisible by {PIXELS_PER_IMAGE_TOKE

Error message

height and width must be divisible by {PIXELS_PER_IMAGE_TOKEN}, got {height}x{width}

What it means

validate_dimensions checks that requested height and width are multiples of PIXELS_PER_IMAGE_TOKEN, because Ideogram4 packs pixels into patch/token grids; non-divisible sizes would break the patchify/VAE grid math.

Source

Thrown at invokeai/backend/ideogram4/sampling_utils.py:48

LATENT_DIM = 128


class Ideogram4DenoiseInputs(TypedDict):
    """The packed-sequence tensors fed to the transformer during denoising."""

    position_ids: torch.Tensor  # (1, L, 3) int64 — (t, h, w) positions for MRoPE
    segment_ids: torch.Tensor  # (1, L) int64 — sample id within the packed batch
    indicator: torch.Tensor  # (1, L) int64 — LLM_TOKEN_INDICATOR or OUTPUT_IMAGE_INDICATOR
    num_text_tokens: int
    num_image_tokens: int
    grid_h: int
    grid_w: int


def validate_dimensions(height: int, width: int) -> None:
    """Ensure the requested resolution is compatible with the patch/VAE grid."""
    if height % PIXELS_PER_IMAGE_TOKEN != 0 or width % PIXELS_PER_IMAGE_TOKEN != 0:
        raise ValueError(f"height and width must be divisible by {PIXELS_PER_IMAGE_TOKEN}, got {height}x{width}")


def build_denoise_inputs(
    num_text_tokens: int,
    height: int,
    width: int,
    device: torch.device,
) -> Ideogram4DenoiseInputs:
    """Build the packed ``[text][image]`` position/segment/indicator tensors for one image.

    Mirrors ``Ideogram4Pipeline._build_inputs`` for batch size 1 (no padding).
    """
    validate_dimensions(height, width)
    grid_h = height // PIXELS_PER_IMAGE_TOKEN
    grid_w = width // PIXELS_PER_IMAGE_TOKEN
    num_image_tokens = grid_h * grid_w
    total_seq_len = num_text_tokens + num_image_tokens

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Round height and width down/up to the nearest multiple of PIXELS_PER_IMAGE_TOKEN before calling
  2. Use one of the model's supported resolution presets
  3. Derive dimensions from a base size multiplied by an integer factor

Example fix

// before
build_denoise_inputs(tokens, 1023, 767)
// after
ppit = PIXELS_PER_IMAGE_TOKEN
h, w = (1023 // ppit) * ppit, (767 // ppit) * ppit
build_denoise_inputs(tokens, h, w)
Defensive patterns

Strategy: validation

Validate before calling

def snap_to_token_grid(h, w, step=PIXELS_PER_IMAGE_TOKEN):
    return max(step, (h // step) * step), max(step, (w // step) * step)
height, width = snap_to_token_grid(height, width)

Type guard

def is_valid_resolution(h: int, w: int) -> bool:
    return h % PIXELS_PER_IMAGE_TOKEN == 0 and w % PIXELS_PER_IMAGE_TOKEN == 0

Try / catch

try:
    build_denoise_inputs(num_text_tokens, height, width)
except ValueError as e:
    if "divisible by" in str(e):
        height, width = snap_to_token_grid(height, width)
        build_denoise_inputs(num_text_tokens, height, width)
    else:
        raise

Prevention

When it happens

Trigger: Calling build_denoise_inputs (or any caller of validate_dimensions) with an arbitrary resolution like 1023x767 instead of a multiple of PIXELS_PER_IMAGE_TOKEN.

Common situations: User-typed custom resolutions in a UI, aspect-ratio presets from other models (e.g. SD sizes like 512x512 when the token size differs), rounding errors when scaling dimensions.

Related errors


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