{"record":{"id":"b2947f34003e33a7","repo":"dotnet/machinelearning","slug":"num-key-value-heads-must-be-specified-b2947f","errorCode":null,"errorMessage":"num_key_value_heads must be specified","messagePattern":"num_key_value_heads must be specified","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.ML.GenAI.Phi/Module/Phi3DecoderLayer.cs","lineNumber":149,"sourceCode":"        hiddenStates = this.mlp.forward(hiddenStates);\n        hiddenStates = residual + this.resid_mlp_dropout.forward(hiddenStates);\n\n        if (UnloadFromDeviceFunc != null)\n        {\n            UnloadFromDeviceFunc(this);\n        }\n        return new Phi3DecoderLayerOutput(hiddenStates.MoveToOuterDisposeScope(), selfAttnWeights?.MoveToOuterDisposeScope(), presentKeyValue);\n    }\n\n    private Attention CreateAttentionFromConfig(Phi3Config config, int layerIdx)\n    {\n        var headDim = config.HiddenSize / config.NumAttentionHeads;\n        return new Attention(\n            attentionDropout: config.AttentionDropout,\n            hiddenSize: config.HiddenSize,\n            numHeads: config.NumAttentionHeads,\n            headDim: headDim,\n            numKeyValueHeads: config.NumKeyValueHeads ?? throw new ArgumentException(\"num_key_value_heads must be specified\"),\n            numKeyValueGroups: config.NumAttentionHeads / config.NumKeyValueHeads ?? throw new ArgumentException(\"num_key_value_heads must be specified\"),\n            maxPositionEmbeddings: config.MaxPositionEmbeddings,\n            originalMaxPositionEmbeddings: config.OriginalMaxPositionEmbeddings,\n            layerIdx: layerIdx,\n            useQkvProj: true,\n            dtype: config.DType);\n    }\n}\n","sourceCodeStart":131,"sourceCodeEnd":158,"githubUrl":"https://github.com/dotnet/machinelearning/blob/7b76e69cf964daeca3f1377af6bc5543284d56c6/src/Microsoft.ML.GenAI.Phi/Module/Phi3DecoderLayer.cs#L131-L158","documentation":"Phi3DecoderLayer.CreateAttentionFromConfig builds the attention module using config.NumKeyValueHeads. When NumKeyValueHeads is null the null-coalescing throw raises ArgumentException('num_key_value_heads must be specified'); Phi-3 requires this field for its GQA layout.","triggerScenarios":"Creating a Phi3DecoderLayer (eager path) with a config.json missing num_key_value_heads, or a programmatically built Phi3Config that left NumKeyValueHeads unset.","commonSituations":"Original Phi-3 checkpoints/exports predating the field; hand-written configs; conversion tools dropping unknown keys.","solutions":["Set NumKeyValueHeads in the config (typically equal to NumAttentionHeads for Phi-3)","Add \"num_key_value_heads\" to the model's config.json before loading","Validate the config right after load and fill defaults: if null, set to NumAttentionHeads"],"exampleFix":"// before\nvar config = Phi3Config.FromFile(\"config.json\");\n// after\nvar config = Phi3Config.FromFile(\"config.json\"); config.NumKeyValueHeads ??= config.NumAttentionHeads;","handlingStrategy":"validation","validationCode":"if (config.NumKeyValueHeads is null) config.NumKeyValueHeads = config.NumAttentionHeads;","typeGuard":"static bool HasGqaFields(Phi3Config c) => c.NumKeyValueHeads is int kv && kv > 0 && c.NumAttentionHeads % kv == 0;","tryCatchPattern":"try { var layer = new Phi3DecoderLayer(config, i); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"num_key_value_heads\")) { config.NumKeyValueHeads = config.NumAttentionHeads; var layer = new Phi3DecoderLayer(config, i); }","preventionTips":["Normalize Phi-3 configs at load time: default NumKeyValueHeads to NumAttentionHeads","Validate divisibility NumAttentionHeads % NumKeyValueHeads == 0","Re-export old checkpoints' config.json with all GQA fields"],"tags":["csharp","phi-3","config"],"backgroundTag":"missing-required-config-field","analyzedSha":"7b76e69cf964daeca3f1377af6bc5543284d56c6","analyzedAt":"2026-09-11T12:35:38.930Z","contentChangedAt":"2026-09-11T12:35:38.930Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}