{"record":{"id":"dacc67041218dc89","repo":"dotnet/machinelearning","slug":"this-is-not-a-causal-mask","errorCode":null,"errorMessage":"This is not a causal mask","messagePattern":"This is not a causal mask","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.ML.GenAI.Core/Utility/AttentionMaskConverter.cs","lineNumber":80,"sourceCode":"        if (causal4dMask is not null)\n        {\n            var min = torch.finfo(dType).min;\n            expandedAttnMask = causal4dMask.masked_fill(expandedAttnMask.to(ScalarType.Bool), min);\n        }\n\n        return expandedAttnMask;\n    }\n\n    public Tensor? ToCausal4D(\n        int batchSize,\n        int queryLength,\n        int keyValueLength,\n        ScalarType dType,\n        Device device)\n    {\n        if (!_isCausal)\n        {\n            throw new ArgumentException(\"This is not a causal mask\");\n        }\n\n        long[] inputShape = [batchSize, queryLength];\n        var pastKeyValueLength = keyValueLength - queryLength;\n\n        // create causal mask\n        // [bsz, seq_len] -> [bsz, 1, tgt_seq_len, src_seq_len]\n        Tensor? causal4DMask = null;\n        if (queryLength > 1 || this._slidingWindow is int)\n        {\n            causal4DMask = MakeCausalMask(inputShape, dType, device, pastKeyValueLength, this._slidingWindow);\n        }\n\n        return causal4DMask;\n    }\n\n    public static Tensor MakeCausalMask(\n        long[] inputIdsShape,","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/dotnet/machinelearning/blob/7b76e69cf964daeca3f1377af6bc5543284d56c6/src/Microsoft.ML.GenAI.Core/Utility/AttentionMaskConverter.cs#L62-L98","documentation":"AttentionMaskConverter.ToCausal4D throws ArgumentException when asked to build a 4D causal mask while the converter's _isCausal flag is false. ToCausal4D is the fallback path used when no 2D attention mask is supplied, and it only makes sense for causal attention.","triggerScenarios":"Calling Create4DCausalAttentionMask with attentionMask == null on a converter constructed with isCausal: false.","commonSituations":"Reusing a bidirectional (non-causal) mask converter in a decoder model where no explicit 2D mask is provided; copy-pasted converter setup from an encoder model into a causal LM pipeline.","solutions":["Construct the AttentionMaskConverter with isCausal: true for decoder/causal models.","Pass an explicit 2D attention mask so the To4D path is used instead.","Verify the model config's is_causal/decoder flag matches the converter flags.","For encoder-style models, don't call ToCausal4D — expand the 2D mask with ExpandMask instead."],"exampleFix":"// before\nvar converter = new AttentionMaskConverter(isCausal: false);\nvar mask4d = converter.ToCausal4D(batchSize, qLen, kvLen, dType, device);\n// after\nvar converter = new AttentionMaskConverter(isCausal: true);\nvar mask4d = converter.ToCausal4D(batchSize, qLen, kvLen, dType, device);","handlingStrategy":"validation","validationCode":"if (!isCausal) throw new InvalidOperationException(\"ToCausal4D requires isCausal: true converter\");","typeGuard":"bool CausalOk(bool isCausal) => isCausal;","tryCatchPattern":"try { var mask = converter.ToCausal4D(batch, qLen, kvLen, dType, device); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"not a causal mask\")) { logger.LogError(\"Converter constructed with isCausal=false; use To4D/ExpandMask instead\"); throw; }","preventionTips":["Set isCausal: true for all decoder (causal LM) models.","Use To4D/ExpandMask paths for encoder-style non-causal masks.","Align converter flags with the model config's decoder flag.","Don't reuse a bidirectional converter instance in generation code."],"tags":["attention","mask","argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"7b76e69cf964daeca3f1377af6bc5543284d56c6","analyzedAt":"2026-09-11T12:35:38.930Z","contentChangedAt":"2026-09-11T12:35:38.930Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}