invoke-ai/InvokeAI · error · ValueError

Qwen-Image PiD decode expected a 16-channel latent, got shap

Error message

Qwen-Image PiD decode expected a 16-channel latent, got shape {tuple(latents.shape)}.

What it means

After frame reduction the invocation validates the latent is 4D with 16 channels (Qwen-Image latent channel count). Anything else (SD-style 4-channel, video latent not reduced, wrong ndim) raises ValueError reporting the actual shape, since the VAE denormalization/decode expects exactly this layout.

Source

Thrown at invokeai/app/invocations/qwen_image_pid_decode.py:135

        # the Nodes editor wire any PiD decoder into this Qwen-Image-specific node).
        assert_pid_decoder_matches_base(
            context.models.get_config(self.pid_decoder.decoder).base,
            BaseModelType.QwenImage,
            node_title="Qwen-Image PiD Decode",
        )

        latents = context.tensors.load(self.latents.latents_name)

        # 1) Reduce the stored 5D (B, C, num_frames, H, W) latent to 2D (B, C, H, W). Qwen's VAE is a video-style
        #    autoencoder; for a single image num_frames == 1 (mirrors qwen_image_l2i's `img[:, :, 0]`).
        if latents.ndim == 5:
            if latents.shape[2] != 1:
                raise ValueError(
                    f"Qwen-Image PiD decode expected a single temporal frame, got shape {tuple(latents.shape)}."
                )
            latents = latents[:, :, 0]
        if latents.ndim != 4 or latents.shape[-3] != 16:
            raise ValueError(f"Qwen-Image PiD decode expected a 16-channel latent, got shape {tuple(latents.shape)}.")

        # 2) Resolve the per-channel latents_mean / latents_std used to denormalise the stored latent.
        latents_mean = list(_QWEN_VAE_LATENTS_MEAN_FALLBACK)
        latents_std = list(_QWEN_VAE_LATENTS_STD_FALLBACK)
        if self.vae is not None:
            vae_info = context.models.load(self.vae.vae)
            with vae_info.model_on_device() as (_, vae):
                config = getattr(vae, "config", None)
                cfg_mean = getattr(config, "latents_mean", None) if config is not None else None
                cfg_std = getattr(config, "latents_std", None) if config is not None else None
                if cfg_mean is not None and cfg_std is not None:
                    latents_mean = [float(x) for x in cfg_mean]
                    latents_std = [float(x) for x in cfg_std]
            del vae_info
            TorchDevice.empty_cache()
        if len(latents_mean) != 16 or len(latents_std) != 16:
            raise ValueError(
                f"Qwen-Image VAE latents_mean/latents_std must have 16 entries, got {len(latents_mean)}/{len(latents_std)}."

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Ensure the upstream denoise/latent node is the Qwen-Image pipeline producing 16-channel 4D latents
  2. Check latents.shape: must be (B, 16, H, W) after any frame reduction
  3. Use the correct model-specific decode node for non-Qwen latents instead of PiD decode
  4. Regenerate the latents with the correct pipeline rather than reusing an old latents_name

Example fix

// before
latents = latents  # (1, 4, 64, 64) SD latent fed to Qwen decode
// after
latents = qwen_denoise.latents  # (1, 16, H, W) Qwen latent
Defensive patterns

Strategy: type-guard

Validate before calling

latents = context.tensors.load(latents_name)
assert latents.ndim == 4 and latents.shape[-3] == 16, f"bad latent: {tuple(latents.shape)}"

Type guard

def is_qwen_image_latent(t: "torch.Tensor") -> bool:
    return t.ndim == 4 and t.shape[-3] == 16

Try / catch

try:
    output = invoke(context)
except ValueError as e:
    if "16-channel latent" in str(e):
        raise RuntimeError("Wire a Qwen-Image 16-channel latent into this node") from e
    raise

Prevention

When it happens

Trigger: Connecting latents from a non-Qwen model (e.g. SD 4-channel) to the Qwen PiD decode node; passing a 5D latent whose ndim/shape wasn't reduced; loading a stale latents file from another pipeline.

Common situations: Mixing model families in one graph (SDXL denoise -> Qwen decode); upgrading InvokeAI where channel conventions changed; hand-edited workflows with mismatched latent nodes.

Related errors


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