{"record":{"id":"6f2fad4342a29aa0","repo":"Comfy-Org/ComfyUI","slug":"attention-mask-must-be-expected-got-tuple-atte","errorCode":null,"errorMessage":"attention_mask must be {expected}, got {tuple(attention_mask.shape)}","messagePattern":"attention_mask must be (.+?), got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy/ldm/lens/model.py","lineNumber":165,"sourceCode":"        txt_qkv = self.txt_qkv(encoder_hidden_states).view(bsz, seq_txt, 3, self.heads, self.dim_head)\n        txt_q, txt_k, txt_v = txt_qkv.unbind(dim=2)\n        txt_q = self.norm_added_q(txt_q)\n        txt_k = self.norm_added_k(txt_k)\n\n        # [B, S, H, D] → [B, H, S, D] for attention, dels to avoid VRAM peaks\n        q = torch.cat([img_q, txt_q], dim=1).transpose(1, 2)\n        del img_q, txt_q\n        k = torch.cat([img_k, txt_k], dim=1).transpose(1, 2)\n        del img_k, txt_k\n        v = torch.cat([img_v, txt_v], dim=1).transpose(1, 2)\n        del img_v, txt_v\n\n        q, k = apply_rope(q, k, freqs_cis)\n\n        if attention_mask is not None:\n            expected = (bsz, 1, 1, seq_img + seq_txt)\n            if attention_mask.shape != expected:\n                raise ValueError(\n                    f\"attention_mask must be {expected}, got {tuple(attention_mask.shape)}\"\n                )\n            attention_mask = attention_mask.to(q.dtype)\n\n        out = optimized_attention(\n            q, k, v, self.heads, mask=attention_mask, skip_reshape=True,\n            transformer_options=transformer_options,\n        )\n\n        img_out = self.to_out[1](self.to_out[0](out[:, :seq_img, :]))\n        txt_out = self.to_add_out(out[:, seq_img:, :])\n        return img_out, txt_out\n\n\nclass LensTransformerBlock(nn.Module):\n    def __init__(\n        self,\n        dim: int,","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy/ldm/lens/model.py#L147-L183","documentation":"The Lens joint img/txt attention block requires an additive attention mask of exactly (bsz, 1, 1, seq_img + seq_txt) so it can be passed straight to optimized_attention with skip_reshape=True. Any other shape is rejected rather than silently broadcasting to wrong tokens.","triggerScenarios":"Passing a (B, S) or (B, 1, S) mask instead of the 4D expanded form, or a mask built against text-only/img-only length; also batch-size mismatches when cond/uncond are combined.","commonSituations":"Custom node authors adapting masks from other architectures (Flux/Wan style masks are (B,S)), or callers reusing a mask computed before sequence lengths were final.","solutions":["Expand your (B, S) mask: mask[:, None, None, :] to match (bsz, 1, 1, seq_img+seq_txt)","Recompute the mask after concatenation order img+txt with the current batch size","Pass attention_mask=None if full attention is intended"],"exampleFix":"# before\nout = block(img, txt, freqs, attention_mask=mask)  # mask is (B, S)\n# after\nmask4 = mask[:, None, None, :].expand(bsz, 1, 1, seq_img + seq_txt)\nout = block(img, txt, freqs, attention_mask=mask4)","handlingStrategy":"validation","validationCode":"S = seq_img + seq_txt\nassert mask is None or tuple(mask.shape) == (bsz, 1, 1, S), mask.shape","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize masks as (B, 1, 1, S) before passing to Lens blocks","Recompute masks after concatenation, never reuse across length changes"],"tags":["lens","attention-mask","shape-mismatch"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}