{"record":{"id":"c5e8b6c55325a53e","repo":"invoke-ai/InvokeAI","slug":"flux-2-pid-decode-expected-a-32-channel-latent-fro","errorCode":null,"errorMessage":"FLUX.2 PiD decode expected a 32-channel latent from flux2_denoise, got shape {tuple(latents.shape)}. The upstream node must output the unpacked FLUX.2 latent.","messagePattern":"FLUX\\.2 PiD decode expected a 32-channel latent from flux2_denoise, got shape (.+?)\\. The upstream node must output the unpacked FLUX\\.2 latent\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/flux2_pid_decode.py","lineNumber":140,"sourceCode":"    @torch.no_grad()\n    def invoke(self, context: InvocationContext) -> ImageOutput:\n        # Fail fast if the connected decoder is for a different backbone (the base-agnostic loader lets\n        # the Nodes editor wire any PiD decoder into this FLUX.2-specific node).\n        assert_pid_decoder_matches_base(\n            context.models.get_config(self.pid_decoder.decoder).base,\n            BaseModelType.Flux2,\n            node_title=\"FLUX.2 PiD Decode\",\n        )\n\n        latents = context.tensors.load(self.latents.latents_name)\n\n        # 1) Patchify the stored FLUX.2 latent into PiD's expected layout.\n        #    flux2_denoise stores an unpacked (B, 32, H/8, W/8) latent; PiD's\n        #    FLUX.2 backbone wants the packed (B, 128, H/16, W/16) form (32*4=128\n        #    channels, spatial halved). This mirrors pack_flux2's 2x2 patchify but\n        #    keeps a spatial (B, C, h, w) layout rather than a (B, seq, C) sequence.\n        if latents.shape[-3] != 32:\n            raise ValueError(\n                f\"FLUX.2 PiD decode expected a 32-channel latent from flux2_denoise, got shape \"\n                f\"{tuple(latents.shape)}. The upstream node must output the unpacked FLUX.2 latent.\"\n            )\n        packed = rearrange(latents, \"b c (h ph) (w pw) -> b (c ph pw) h w\", ph=2, pw=2)\n        context.logger.info(\n            f\"FLUX.2 PiD decode: stored latent shape={tuple(latents.shape)} -> packed for PiD \"\n            f\"shape={tuple(packed.shape)} (expect [B, 128, H/16, W/16]) dtype={packed.dtype}\"\n        )\n\n        # 2) Resolve the scalar scaling/shift (identity for current FLUX.2 VAEs).\n        scaling_factor = _FLUX2_VAE_SCALING_FACTOR_FALLBACK\n        shift_factor = _FLUX2_VAE_SHIFT_FACTOR_FALLBACK\n        if self.vae is not None:\n            vae_info = context.models.load(self.vae.vae)\n            with vae_info.model_on_device() as (_, vae):\n                config = getattr(vae, \"config\", None)\n                if config is not None and hasattr(config, \"scaling_factor\"):\n                    scaling_factor = float(config.scaling_factor)","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/flux2_pid_decode.py#L122-L158","documentation":"The FLUX.2 PiD decoder expects the unpacked FLUX.2 latent layout with 32 channels, (B, 32, H/8, W/8), as produced by flux2_denoise. It patchifies it internally to the packed (B, 128, H/16, W/16) form. A latent with any other channel count means the wrong tensor was fed to the decode node.","triggerScenarios":"latents.shape[-3] != 32 in invoke; connecting a node that outputs a packed/seq-layout FLUX.2 latent (128 channels or sequence form) or a latent from a different model family directly into the PiD decode invocation's latents input.","commonSituations":"Wiring flux2_denoise output through a reshaping node first; using a generic VAE decode output as input; pipeline graphs copied from FLUX.1 where latent channels differ; manually constructing latents in a custom script.","solutions":["Connect the latents input directly to the FLUX.2 flux2_denoise output","Do not apply pack_flux2 or any packing/reshaping before this node (packing happens internally)","Verify the upstream denoise node is the FLUX.2 variant, not FLUX.1 or SD","Check no custom nodes alter channel count between denoise and decode"],"exampleFix":"// before: pre-packed latent fed to PiD decode\npacked = pack_flux2(latents); pid_decode(latents=packed)\n// after: raw flux2_denoise output\npid_decode(latents=denoise_output.latents)","handlingStrategy":"validation","validationCode":"latents = context.images.get_latents(denoise_output.latents)\nif latents.latents.shape[-3] != 32:\n    raise ValueError(f'Expected 32-channel FLUX.2 latent, got {latents.latents.shape}')","typeGuard":"def is_unpacked_flux2_latent(latents: torch.Tensor) -> bool:\n    return latents.ndim == 4 and latents.shape[-3] == 32","tryCatchPattern":"try:\n    result = pid_decode.invoke(context)\nexcept ValueError as e:\n    if '32-channel latent' in str(e):\n        reroute_from_flux2_denoise_output()\n    raise","preventionTips":["Always connect latents directly from the FLUX.2 flux2_denoise node","Never apply pack_flux2 before PiD decode","Check channel counts when adapting FLUX.1 graphs"],"tags":["latent","shape-mismatch","pipeline"],"backgroundTag":"latent-shape-mismatch","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}