{"record":{"id":"0988b9dfbe49a896","repo":"Comfy-Org/ComfyUI","slug":"input-img-and-txt-tensors-must-have-3-dimensions","errorCode":null,"errorMessage":"Input img and txt tensors must have 3 dimensions.","messagePattern":"Input img and txt tensors must have 3 dimensions\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"critical","filePath":"comfy/ldm/chroma/model.py","lineNumber":284,"sourceCode":"            final_mod = self.get_modulations(mod_vectors, \"final\")\n            img = self.final_layer(img, vec=final_mod)  # (N, T, patch_size ** 2 * out_channels)\n        return img\n\n    def forward(self, x, timestep, context, guidance, control=None, transformer_options={}, **kwargs):\n        return comfy.patcher_extension.WrapperExecutor.new_class_executor(\n            self._forward,\n            self,\n            comfy.patcher_extension.get_all_wrappers(comfy.patcher_extension.WrappersMP.DIFFUSION_MODEL, transformer_options)\n        ).execute(x, timestep, context, guidance, control, transformer_options, **kwargs)\n\n    def _forward(self, x, timestep, context, guidance, control=None, transformer_options={}, **kwargs):\n        bs, c, h, w = x.shape\n        x = comfy.ldm.common_dit.pad_to_patch_size(x, (self.patch_size, self.patch_size))\n\n        img = rearrange(x, \"b c (h ph) (w pw) -> b (h w) (c ph pw)\", ph=self.patch_size, pw=self.patch_size)\n\n        if img.ndim != 3 or context.ndim != 3:\n            raise ValueError(\"Input img and txt tensors must have 3 dimensions.\")\n\n        h_len = ((h + (self.patch_size // 2)) // self.patch_size)\n        w_len = ((w + (self.patch_size // 2)) // self.patch_size)\n        img_ids = torch.zeros((h_len, w_len, 3), device=x.device, dtype=x.dtype)\n        img_ids[:, :, 1] = img_ids[:, :, 1] + torch.linspace(0, h_len - 1, steps=h_len, device=x.device, dtype=x.dtype).unsqueeze(1)\n        img_ids[:, :, 2] = img_ids[:, :, 2] + torch.linspace(0, w_len - 1, steps=w_len, device=x.device, dtype=x.dtype).unsqueeze(0)\n        img_ids = repeat(img_ids, \"h w c -> b (h w) c\", b=bs)\n\n        txt_ids = torch.zeros((bs, context.shape[1], 3), device=x.device, dtype=x.dtype)\n        out = self.forward_orig(img, img_ids, context, txt_ids, timestep, guidance, control, transformer_options, attn_mask=kwargs.get(\"attention_mask\", None))\n        return rearrange(out, \"b (h w) (c ph pw) -> b c (h ph) (w pw)\", h=h_len, w=w_len, ph=self.patch_size, pw=self.patch_size)[:,:,:h,:w]\n","sourceCodeStart":266,"sourceCodeEnd":296,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy/ldm/chroma/model.py#L266-L296","documentation":"Chroma's _forward patchifies the input latent to img tokens of shape [B, seq, c*ph*pw] and expects the text context to already be [B, seq_txt, dim]. If either tensor is not 3-D after patchify/rearrange, downstream attention (img-txt concatenation, RoPE) would silently mis-broadcast, so an explicit ValueError guards it. In practice the check fires on context.ndim != 3 far more often than on img, because img is reshaped one line above into 3-D unconditionally.","triggerScenarios":"Calling Chroma._forward with context that is 2-D (a single unbatched text embedding [seq, dim]) or 4-D (e.g. an image-shaped tensor passed as conditioning), or with a non-square/padded latent whose rearrange produces something unexpected. Direct calls from custom code hit this; the normal ComfyUI sampling path always passes batched [B, S, D] context.","commonSituations":"Custom nodes calling the diffusion model forward directly with unbatched CLIP/Qwen embeddings; feeding a per-prompt context list instead of a stacked tensor; patches that skip the standard conditioning pipeline.","solutions":["Unsqueeze the context to batch format: context = context.unsqueeze(0).expand(bs, -1, -1) before calling forward","Pass a latent tensor of shape [B, C, H, W] as x and let _forward do the patchify itself","Use the standard ComfyUI sampling entry points (samplers in comfy/samplers.py) instead of calling _forward directly"],"exampleFix":"# before\nout = model._forward(x, t, context=text_emb)  # text_emb: [S, D] -> raises\n\n# after\nif context.ndim == 2:\n    context = context.unsqueeze(0)\nout = model._forward(x, t, context=context)","handlingStrategy":"validation","validationCode":"def ensure_batched_context(context, bs):\n    if context.ndim == 2:\n        context = context.unsqueeze(0)\n    if context.shape[0] == 1 and bs > 1:\n        context = context.expand(bs, -1, -1)\n    assert context.ndim == 3\n    return context","typeGuard":"def is_3d_batched(t) -> bool:\n    return isinstance(t, torch.Tensor) and t.ndim == 3","tryCatchPattern":null,"preventionTips":["Always pass [B, C, H, W] latents and [B, S, D] conditioning into model forwards","Prefer the standard ComfyUI sampling path over direct _forward calls"],"tags":["chroma","tensor-shape","conditioning","forward"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}