{"record":{"id":"cfaf7cc1353f4c0c","repo":"Comfy-Org/ComfyUI","slug":"pose-branch-has-latent-frames-expected-gen","errorCode":null,"errorMessage":"pose branch has {} latent frames, expected {} (generation frames minus the reference-image slot)","messagePattern":"pose branch has (.+?) latent frames, expected (.+?) \\(generation frames minus the reference-image slot\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy/ldm/wan/model_animate2.py","lineNumber":293,"sourceCode":"            w_patches = (w + (self.patch_size[2] // 2)) // self.patch_size[2]\n            freqs_pose = self.rope_encode_pose(pose_latents.shape[2], h, w, w_patches, device=x.device, dtype=x.dtype)\n\n        return self.forward_orig(x, timestep, context, clip_fea=clip_fea, freqs=freqs, freqs_pose=freqs_pose, pose_latents=pose_latents,\n                                 clip_fea_pose=clip_fea_pose, context_pose=context_pose, transformer_options=transformer_options, **kwargs)[:, :, :t, :h, :w]\n\n    def forward_orig(self, x, t, context, clip_fea=None, freqs=None, freqs_pose=None, pose_latents=None, clip_fea_pose=None, context_pose=None, pose_strength=1.0, reference_strength=1.0, transformer_options={}, **kwargs):\n        x_input = x[:, :, 1:]  # video-only: frame 0 is the reference slot, offset past it below\n        x = self.patch_embedding(x.float()).to(x.dtype)\n        grid_sizes = x.shape[2:]\n        transformer_options[\"grid_sizes\"] = grid_sizes\n        f_gen, gh, gw = grid_sizes\n        hw = gh * gw\n        x = x.flatten(2).transpose(1, 2)\n\n        # the node windows the pose influence via cond timestep ranges: outside the window the cond carries no pose latents, and the branch, its cache traffic and the per-frame attention loop are all skipped\n        apply_pose = pose_latents is not None\n        if apply_pose and pose_latents.shape[2] != f_gen - 1:  # before cache.select, which would otherwise keep an empty slot keyed to the rejected latents\n            raise ValueError(\"pose branch has {} latent frames, expected {} (generation frames minus the reference-image slot)\".format(pose_latents.shape[2], f_gen - 1))\n\n        cache = transformer_options.get(\"animate2_cache\", None) if apply_pose else None\n        if cache is not None:\n            cache.select(pose_latents)\n        cached = cache is not None and cache.filled(len(self.blocks))\n\n        x_pose = None\n        if not cached and apply_pose:\n            # 36ch = [latents(16) | mask(4) | latents(16)]; latents twice, and the mask is all ones since every pose frame is known\n            x_pose = self.patch_embedding(torch.cat([pose_latents, torch.ones_like(pose_latents[:, :4]), pose_latents], dim=1).float()).to(x.dtype)\n            x_pose = x_pose.flatten(2).transpose(1, 2)\n\n        # time embeddings\n        e = self.time_embedding(sinusoidal_embedding_1d(self.freq_dim, t.flatten()).to(dtype=x.dtype))\n        e = e.reshape(t.shape[0], -1, e.shape[-1])\n        e0 = self.time_projection(e).unflatten(2, (6, self.dim))\n\n        e0_pose = None","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy/ldm/wan/model_animate2.py#L275-L311","documentation":"Wan Animate 2's forward expects pose latents to cover exactly the generation frames minus the reference-image slot (f_gen - 1), because frame 0 of the main latent is the reference slot. A mismatch means the pose conditioning was generated for a different frame count than the video being denoised; the check runs before the animate2 cache select so the cache never keys a rejected latent set.","triggerScenarios":"Calling the model with pose_latents whose shape[2] != f_gen - 1 — e.g. pose video has a different length/slip than the generation video, the reference frame was not accounted for, or a length/slip change was made after the pose latents were encoded.","commonSituations":"Changing the generation length or the last-frame setting without re-encoding the pose branch; pose video frame count not matching (generation frames - 1); stale cached pose latents from an earlier config.","solutions":["Re-encode the pose latents so they cover exactly the generation frames (video frames minus the reference slot).","Keep the pose clip's effective frame count in sync with length/slip settings used for generation.","Outside a pose cond window, omit pose_latents entirely (pass None) rather than a mismatched tensor."],"exampleFix":"# before\npose_latents = encode_pose(pose_clip)  # encoded for old length\nout = model(x, t, ctx, pose_latents=pose_latents)  # x implies different f_gen\n# after\npose_latents = encode_pose(pose_clip_for_current_length)  # T == f_gen - 1\nout = model(x, t, ctx, pose_latents=pose_latents)","handlingStrategy":"validation","validationCode":"f_gen, gh, gw = grid_sizes  # or compute expected count from video length\nif pose_latents is not None and pose_latents.shape[2] != f_gen - 1:\n    raise ValueError(f\"pose frames {pose_latents.shape[2]} != generation frames {f_gen - 1}; re-encode pose\")","typeGuard":"def pose_matches_generation(pose_latents, f_gen) -> bool:\n    return pose_latents is None or pose_latents.shape[2] == f_gen - 1","tryCatchPattern":null,"preventionTips":["Re-encode pose latents whenever length, slip, or reference-frame settings change.","Pass pose_latents=None outside the pose conditioning window instead of stale tensors."],"tags":["wan","animate2","pose","shape-mismatch","conditioning"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}