{"record":{"id":"d4e729a7256ff551","repo":"dotnet/machinelearning","slug":"unsupported-role-message-role-d4e729","errorCode":null,"errorMessage":"Unsupported role {message.Role}","messagePattern":"Unsupported role (.+?)","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.ML.GenAI.Phi/Phi3/Phi3ChatTemplateBuilder.cs","lineNumber":80,"sourceCode":"    {\n        // build prompt from chat history\n        var sb = new StringBuilder();\n\n        foreach (var message in chatHistory)\n        {\n            foreach (var item in message.Items)\n            {\n                if (item is not TextContent textContent)\n                {\n                    throw new NotSupportedException($\"Only text content is supported, but got {item.GetType().Name}\");\n                }\n\n                var prompt = message.Role switch\n                {\n                    _ when message.Role == AuthorRole.System => $\"<|system|>{Newline}{textContent}<|end|>{Newline}\",\n                    _ when message.Role == AuthorRole.User => $\"<|user|>{Newline}{textContent}<|end|>{Newline}\",\n                    _ when message.Role == AuthorRole.Assistant => $\"<|assistant|>{Newline}{textContent}<|end|>{Newline}\",\n                    _ => throw new NotSupportedException($\"Unsupported role {message.Role}\")\n                };\n\n                sb.Append(prompt);\n            }\n        }\n\n        sb.Append(\"<|assistant|>\");\n\n        return sb.ToString();\n    }\n\n    public string BuildPrompt(IEnumerable<ChatMessage> messages, ChatOptions? options = null, bool appendAssistantTag = true)\n    {\n        var availableRoles = new[] { ChatRole.System, ChatRole.User, ChatRole.Assistant };\n        if (messages.Any(m => m.Text is null))\n        {\n            throw new InvalidOperationException(\"Please provide a message with content.\");\n        }","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/dotnet/machinelearning/blob/7b76e69cf964daeca3f1377af6bc5543284d56c6/src/Microsoft.ML.GenAI.Phi/Phi3/Phi3ChatTemplateBuilder.cs#L62-L98","documentation":"In the ChatMessage overload of BuildPrompt, each item's prompt is selected by the message's AuthorRole. If the role is not System, User, or Assistant, the discard arm throws NotSupportedException('Unsupported role ...'). The trailing newline interpolates the actual role value into the message.","triggerScenarios":"Calling BuildPrompt(IEnumerable<ChatMessage>) with a message whose AuthorRole is Tool, Function, or any custom role string outside the three supported Phi-3 roles.","commonSituations":"Tool-result messages in the chat history; custom roles defined by the host application; histories exported from frameworks with richer role vocabularies.","solutions":["Map unsupported roles onto User or Assistant before building the prompt.","Filter messages to the three supported roles.","Serialize tool results as assistant/user text messages."],"exampleFix":"// before\nvar prompt = builder.BuildPrompt(chatHistory); // contains Tool role\n// after\nvar normalized = chatHistory.Select(m => m.Role == AuthorRole.Tool ? new ChatMessage(AuthorRole.User, m.Content) : m);\nvar prompt = builder.BuildPrompt(normalized);","handlingStrategy":"validation","validationCode":"var supported = new[] { AuthorRole.System, AuthorRole.User, AuthorRole.Assistant };\nif (chatHistory.Any(m => !supported.Contains(m.Role)))\n    throw new InvalidOperationException($\"Unsupported role in history: {chatHistory.First(m => !supported.Contains(m.Role)).Role}\");","typeGuard":"bool HasSupportedRole(ChatMessage m) => m.Role == AuthorRole.System || m.Role == AuthorRole.User || m.Role == AuthorRole.Assistant;","tryCatchPattern":"try { var prompt = builder.BuildPrompt(chatHistory); } catch (NotSupportedException ex) when (ex.Message.StartsWith(\"Unsupported role\")) { chatHistory = chatHistory.Where(HasSupportedRole).ToList(); prompt = builder.BuildPrompt(chatHistory); }","preventionTips":["Map tool/custom roles to User or Assistant at history-ingestion time.","Restrict role creation to the three supported AuthorRole values.","Log and drop unsupported-role messages instead of passing them through."],"tags":["csharp","llm","chat-template","roles"],"backgroundTag":"unsupported-enum-value","analyzedSha":"7b76e69cf964daeca3f1377af6bc5543284d56c6","analyzedAt":"2026-09-11T12:35:38.930Z","contentChangedAt":"2026-09-11T12:35:38.930Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}