{"record":{"id":"df634ce22ee95ef7","repo":"invoke-ai/InvokeAI","slug":"latent-channel-mismatch-these-latents-have-laten","errorCode":null,"errorMessage":"Latent channel mismatch: these latents have {latents.shape[1]} channels but the selected VAE expects {vae.config.z_dim}. A14B models need the 16-channel Wan 2.1 VAE; TI2V-5B needs the 48-channel Wan 2.2 VAE.","messagePattern":"Latent channel mismatch: these latents have (.+?) channels but the selected VAE expects (.+?)\\. A14B models need the 16-channel Wan 2\\.1 VAE; TI2V-5B needs the 48-channel Wan 2\\.2 VAE\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/wan_latents_to_image.py","lineNumber":98,"sourceCode":"            pixel_frames=1,\n        )\n\n        with vae_info.model_on_device(working_mem_bytes=estimated_working_memory) as (_, vae):\n            context.util.signal_progress(\"Running Wan VAE decode\")\n            assert isinstance(vae, AutoencoderKLWan)\n\n            vae_dtype = next(iter(vae.parameters())).dtype\n            latents = latents.to(device=get_effective_device(vae), dtype=vae_dtype)\n\n            TorchDevice.empty_cache()\n\n            with torch.inference_mode():\n                # Re-add the temporal dim if upstream squeezed it out.\n                if latents.ndim == 4:\n                    latents = latents.unsqueeze(2)\n\n                if latents.shape[1] != vae.config.z_dim:\n                    raise ValueError(\n                        f\"Latent channel mismatch: these latents have {latents.shape[1]} channels but the \"\n                        f\"selected VAE expects {vae.config.z_dim}. A14B models need the 16-channel Wan 2.1 \"\n                        \"VAE; TI2V-5B needs the 48-channel Wan 2.2 VAE.\"\n                    )\n\n                # Denormalise from denoiser space back to raw VAE space.\n                latents_mean = torch.tensor(vae.config.latents_mean).view(1, -1, 1, 1, 1).to(latents)\n                latents_std = torch.tensor(vae.config.latents_std).view(1, -1, 1, 1, 1).to(latents)\n                latents = latents * latents_std + latents_mean\n\n                decoded = vae.decode(latents, return_dict=False)[0]\n\n                if decoded.ndim == 5:\n                    decoded = decoded.squeeze(2)\n\n            img = decoded.clamp(-1, 1)\n            img = rearrange(img[0], \"c h w -> h w c\")\n            img_pil = Image.fromarray((127.5 * (img + 1.0)).byte().cpu().numpy())","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/wan_latents_to_image.py#L80-L116","documentation":"This ValueError is thrown by the Wan latents-to-image invocation when the latent tensor's channel count does not match the z_dim configured on the selected Wan VAE. InvokeAI enforces this because Wan 2.1 A14B models use a 16-channel latent space while the Wan 2.2 TI2V-5B model uses a 48-channel latent space, and decoding latents through a mismatched VAE would silently produce garbage.","triggerScenarios":"Calling invoke() on wan_latents_to_image with a latents tensor whose shape[1] differs from vae.config.z_dim after the 4D->5D promotion (unsqueeze of the temporal dim). Typically latents produced by a Wan 2.1 denoiser (16ch) paired with the 48-channel Wan 2.2 VAE, or vice versa.","commonSituations":"Mixing Wan 2.1 and Wan 2.2 checkpoints in one workflow; switching a TI2V-5B pipeline to A14B without swapping the VAE node; an older workflow template referencing the wrong VAE model after an upgrade.","solutions":["Select the VAE matching the latents' origin: 16-channel Wan 2.1 VAE for A14B latents, 48-channel Wan 2.2 VAE for TI2V-5B latents.","Check latents.shape[1] before invoking and route to the correct VAE node.","Regenerate the latents with a denoiser whose latent space matches the chosen VAE.","Update stale workflow templates that hardcode the wrong VAE model ID."],"exampleFix":"// before\nlatents = wan21_denoiser_output  # 16 channels\nvae = load_vae(\"wan2.2-ti2v-5b-vae\")  # z_dim = 48\nimage = wan_latents_to_image(latents=latents, vae=vae)  # ValueError\n// after\nassert latents.shape[1] == 16\nvae = load_vae(\"wan2.1-a14b-vae\")  # z_dim = 16\nimage = wan_latents_to_image(latents=latents, vae=vae)","handlingStrategy":"validation","validationCode":"def validate_latent_channels(latents, vae):\n    z_dim = vae.config.z_dim\n    if latents.shape[1] != z_dim:\n        raise ValueError(\n            f\"Latents have {latents.shape[1]} channels; VAE expects {z_dim}. \"\n            \"A14B -> 16ch Wan 2.1 VAE; TI2V-5B -> 48ch Wan 2.2 VAE.\"\n        )","typeGuard":"def is_wan_latent_compatible(latents, vae) -> bool:\n    return latents.ndim in (4, 5) and latents.shape[1] == vae.config.z_dim","tryCatchPattern":"try:\n    result = node.invoke(context)\nexcept ValueError as e:\n    if \"Latent channel mismatch\" in str(e):\n        vae = pick_vae_for_channels(latents.shape[1])\n        result = replace(node, vae=vae).invoke(context)\n    else:\n        raise","preventionTips":["Pin one VAE per Wan model lineage in your workflow (2.1 A14B vs 2.2 5B).","Assert latents.shape[1] == vae.config.z_dim before every invoke.","Never reuse VAE nodes across Wan 2.1/2.2 workflows.","Name model IDs with the variant to avoid mis-selection."],"tags":["wan","vae","shape-mismatch","latent-channels"],"backgroundTag":"latent-channel-mismatch","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}