invoke-ai/InvokeAI · error · ValueError

num_frames must satisfy (num_frames - 1) %% 4 == 0 for the W

Error message

num_frames must satisfy (num_frames - 1) %% 4 == 0 for the Wan VAE's temporal compression (got {self.num_frames}). Try 5, 9, 13, ..., 81, 85, ...

What it means

The Wan Reference Image invocation validates that the requested video frame count is compatible with the Wan VAE's 4x temporal compression: the latent time axis requires (num_frames - 1) to be divisible by 4. InvokeAI raises this ValueError before any encoding work so the user gets an immediate, actionable message instead of a cryptic shape mismatch deep in the VAE.

Source

Thrown at invokeai/app/invocations/wan_ref_image_encoder.py:110

        default=1,
        ge=1,
        description="Pixel-frame count to build the condition for. Use 1 for single-frame image "
        "I2V. For video I2V, set this to match the video-denoise node's num_frames (and ensure "
        "(num_frames - 1) %% 4 == 0, e.g. 81).",
        title="Number of Frames",
    )
    end_image: Optional[ImageField] = InputField(
        default=None,
        description="Optional end frame for first-last-frame interpolation (FLF2V). When set, the "
        "video interpolates from the reference image (first frame) to this image (final frame). "
        "I2V-A14B video only (num_frames > 1); not supported for TI2V-5B or single-frame I2V.",
        title="End Image (FLF2V)",
    )

    @torch.no_grad()
    def invoke(self, context: InvocationContext) -> WanRefImageOutput:
        if self.num_frames > 1 and (self.num_frames - 1) % 4 != 0:
            raise ValueError(
                f"num_frames must satisfy (num_frames - 1) %% 4 == 0 for the Wan VAE's temporal "
                f"compression (got {self.num_frames}). Try 5, 9, 13, ..., 81, 85, ..."
            )

        pil_image = context.images.get_pil(self.image.image_name, "RGB")
        end_pil_image = context.images.get_pil(self.end_image.image_name, "RGB") if self.end_image is not None else None

        vae_info = context.models.load(self.vae.vae)
        if not isinstance(vae_info.model, AutoencoderKLWan):
            raise TypeError(f"Reference-image encoder requires AutoencoderKLWan, got {type(vae_info.model).__name__}.")

        estimated_working_memory = estimate_vae_working_memory_wan(
            operation="encode",
            vae=vae_info.model,
            pixel_height=self.height,
            pixel_width=self.width,
            pixel_frames=self.num_frames,
        )

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Change num_frames to the nearest valid value of the form 4n+1 (5, 9, 13, 17, ..., 81, 85).
  2. If you need exactly 60 frames, render 57 or 61 frames and trim/duplicate one frame in post.
  3. Keep num_frames = 1 for single-frame image conditioning, which bypasses the check.

Example fix

// before
num_frames = 60  # (60 - 1) % 4 != 0
// after
num_frames = 61  # 4n+1, valid for Wan VAE temporal compression
Defensive patterns

Strategy: validation

Validate before calling

def valid_wan_num_frames(n: int) -> bool:
    return n == 1 or (n - 1) % 4 == 0
if not valid_wan_num_frames(num_frames):
    num_frames = max(5, ((num_frames - 1) // 4) * 4 + 1)

Try / catch

try:
    out = encoder.invoke(context)
except ValueError as e:
    if "num_frames must satisfy" in str(e):
        num_frames = ((num_frames - 1) // 4) * 4 + 1  # snap to 4n+1
    else:
        raise

Prevention

When it happens

Trigger: Calling the 'Reference Image - Wan 2.2' (wan_ref_image_encoder) invocation with num_frames set to a value > 1 where (num_frames - 1) % 4 != 0, e.g. 6, 10, 30, 60.

Common situations: Users pick '60 frames for 2 seconds at 30fps' or copy frame counts from other video tools whose VAEs don't have the 4x temporal constraint; only 4n+1 counts (5, 9, 13, ..., 81, 85) are valid.

Related errors


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