{"record":{"id":"2b32595f0cf490af","repo":"invoke-ai/InvokeAI","slug":"expected-4-d-latent-b-c-h-w-after-extraction","errorCode":null,"errorMessage":"Expected 4-D latent (B, C, H, W) after extraction, got shape {latent.shape}","messagePattern":"Expected 4-D latent \\(B, C, H, W\\) after extraction, got shape (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/pid/_src/inference/pipeline_registry.py","lineNumber":316,"sourceCode":"        # _unpack_latents_with_ids returns a list/stacked tensor (B, C, H, W)\n        latent = result if isinstance(result, torch.Tensor) else torch.stack(result, dim=0)\n    elif cfg.name == \"qwenimage\":\n        # QwenImage: packed (B, seq_len, C) → (B, C, 1, H, W) with temporal dim\n        from diffusers.pipelines.qwenimage.pipeline_qwenimage import QwenImagePipeline\n\n        latent = QwenImagePipeline._unpack_latents(\n            latent,\n            height=height,\n            width=width,\n            vae_scale_factor=pipeline.vae_scale_factor,\n        )\n        # Squeeze temporal dim: (B, C, 1, H, W) → (B, C, H, W)\n        latent = latent.squeeze(2)\n\n    # ZImage: already (B, C, H, W), no unpacking needed.\n\n    if latent.ndim != 4:\n        raise RuntimeError(f\"Expected 4-D latent (B, C, H, W) after extraction, got shape {latent.shape}\")\n    return latent\n\n\ndef decode_with_pipeline_vae(pipeline, latent: torch.Tensor, cfg: DiffusionPipelineConfig) -> torch.Tensor:\n    \"\"\"Standard VAE decode using the pipeline's own VAE.\n\n    Takes the *normalized* latent (as returned by output_type=\"latent\"),\n    denormalizes it, and decodes to pixel space.\n\n    Returns: (B, 3, H, W) float tensor in [0, 1].\n    \"\"\"\n    raw_latent = denormalize_latent(pipeline, latent, cfg)\n\n    if cfg.uses_bn_normalization:\n        # Flux2 VAE: unpatch before decoding.\n        # raw_latent is (B, C_packed, pH, pW) — C_packed = latent_channels * patch_h * patch_w.\n        # Must undo patchification to get (B, latent_channels, H/8, W/8) before vae.decode().\n        from diffusers.pipelines.flux2.pipeline_flux2 import Flux2Pipeline","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/pid/_src/inference/pipeline_registry.py#L298-L334","documentation":"extract_latent unpacks a pipeline's raw latent output (optionally squeezing a temporal dim for video models) and requires the final tensor to be 4-D in (B, C, H, W) layout. Any other rank means the pipeline returned an unexpected structure, so a RuntimeError is raised rather than decoding garbage.","triggerScenarios":"Calling extract_latent with a pipeline whose latent output is not (B, C, H, W) and not a (B, C, 1, H, W) video latent — e.g. a 3-D latent (C, H, W) from a batch-size-1 pipeline that skips the batch dim, a 5-D latent with temporal dim != 1, or a custom pipeline returning tuples/dicts the extractor mis-unpacked.","commonSituations":"Using a custom or third-party pipeline whose output layout differs from the supported backbones; batch-of-videos latents (B, C, T, H, W) with T > 1; forgetting to index into a pipeline output before passing it to extract_latent.","solutions":["Index/select the latent you want first — for video latents pass a single frame (squeeze/slice the temporal dim to size 1).","Confirm the pipeline is one of the supported backbones in PIPELINE_REGISTRY; wrap custom pipelines to emit (B, C, H, W).","If you get a 3-D tensor, unsqueeze a batch dim: latent.unsqueeze(0)."],"exampleFix":"// before: 5-D video latent\nlatent = pipe_output.frames_latent  # (B, C, T, H, W), T > 1\nextract_latent(latent)\n// after\nlatent = pipe_output.frames_latent[:, :, 0]  # (B, C, H, W)\nextract_latent(latent)","handlingStrategy":"type-guard","validationCode":"def ensure_bchw(latent: 'torch.Tensor') -> 'torch.Tensor':\n    if latent.ndim == 5 and latent.shape[2] == 1:\n        latent = latent.squeeze(2)\n    if latent.ndim == 3:\n        latent = latent.unsqueeze(0)\n    if latent.ndim != 4:\n        raise ValueError(f'cannot normalize latent to (B,C,H,W): {latent.shape}')\n    return latent","typeGuard":"def is_bchw(latent: 'torch.Tensor') -> bool:\n    return latent.ndim == 4  # (B, C, H, W)","tryCatchPattern":"try:\n    latent = extract_latent(raw)\nexcept RuntimeError as e:\n    if 'Expected 4-D latent' in str(e):\n        logger.error('Unexpected latent shape: %s', e)\n        latent = extract_latent(normalize_to_bchw(raw))\n    else:\n        raise","preventionTips":["Assert latent.ndim == 4 (or 5 with T=1) at pipeline boundaries before calling extract_latent.","For video pipelines, select a single frame's latent before extraction.","Only pass latents from pipelines in PIPELINE_REGISTRY or adapters that emit (B, C, H, W)."],"tags":["runtime-error","tensor-shape","latent","pid"],"backgroundTag":"unexpected-tensor-shape","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}