invoke-ai/InvokeAI · error · ValueError
FLUX.2 PiD decode expected a 32-channel latent from flux2_de
Error message
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. What it means
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.
Source
Thrown at invokeai/app/invocations/flux2_pid_decode.py:140
@torch.no_grad()
def invoke(self, context: InvocationContext) -> ImageOutput:
# Fail fast if the connected decoder is for a different backbone (the base-agnostic loader lets
# the Nodes editor wire any PiD decoder into this FLUX.2-specific node).
assert_pid_decoder_matches_base(
context.models.get_config(self.pid_decoder.decoder).base,
BaseModelType.Flux2,
node_title="FLUX.2 PiD Decode",
)
latents = context.tensors.load(self.latents.latents_name)
# 1) Patchify the stored FLUX.2 latent into PiD's expected layout.
# flux2_denoise stores an unpacked (B, 32, H/8, W/8) latent; PiD's
# FLUX.2 backbone wants the packed (B, 128, H/16, W/16) form (32*4=128
# channels, spatial halved). This mirrors pack_flux2's 2x2 patchify but
# keeps a spatial (B, C, h, w) layout rather than a (B, seq, C) sequence.
if latents.shape[-3] != 32:
raise ValueError(
f"FLUX.2 PiD decode expected a 32-channel latent from flux2_denoise, got shape "
f"{tuple(latents.shape)}. The upstream node must output the unpacked FLUX.2 latent."
)
packed = rearrange(latents, "b c (h ph) (w pw) -> b (c ph pw) h w", ph=2, pw=2)
context.logger.info(
f"FLUX.2 PiD decode: stored latent shape={tuple(latents.shape)} -> packed for PiD "
f"shape={tuple(packed.shape)} (expect [B, 128, H/16, W/16]) dtype={packed.dtype}"
)
# 2) Resolve the scalar scaling/shift (identity for current FLUX.2 VAEs).
scaling_factor = _FLUX2_VAE_SCALING_FACTOR_FALLBACK
shift_factor = _FLUX2_VAE_SHIFT_FACTOR_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)
if config is not None and hasattr(config, "scaling_factor"):
scaling_factor = float(config.scaling_factor)View on GitHub (pinned to 0b6a024f2f)
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
Example fix
// before: pre-packed latent fed to PiD decode packed = pack_flux2(latents); pid_decode(latents=packed) // after: raw flux2_denoise output pid_decode(latents=denoise_output.latents)
Defensive patterns
Strategy: validation
Validate before calling
latents = context.images.get_latents(denoise_output.latents)
if latents.latents.shape[-3] != 32:
raise ValueError(f'Expected 32-channel FLUX.2 latent, got {latents.latents.shape}') Type guard
def is_unpacked_flux2_latent(latents: torch.Tensor) -> bool:
return latents.ndim == 4 and latents.shape[-3] == 32 Try / catch
try:
result = pid_decode.invoke(context)
except ValueError as e:
if '32-channel latent' in str(e):
reroute_from_flux2_denoise_output()
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Incompatible 'noise' and 'latents' shapes: ${latents.shape=}
- Krea-2 conditioning mask shape {tuple(mask.shape)} does not
- All Krea-2 conditioning batch items must have the same valid
- Expected noise with shape {expected_shape}, got {tuple(noise
- Wan image denoise expects initial latent dimensions {expecte
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/c5e8b6c55325a53e.
Report an issue: GitHub.