dotnet/machinelearning · error · InvalidOperationException
Please provide a message with a valid role. The valid roles
Error message
Please provide a message with a valid role. The valid roles are System, User, and Assistant.
What it means
BuildPrompt(IEnumerable<IMessage>) restricts messages to Role.System, Role.User, and Role.Assistant, matching the Phi-3 chat format. A message with a null role or any other role (e.g. Tool, Function) causes this InvalidOperationException.
Source
Thrown at src/Microsoft.ML.GenAI.Phi/Phi3/Phi3ChatTemplateBuilder.cs:35
namespace Microsoft.ML.GenAI.Phi;
public class Phi3ChatTemplateBuilder : IChatTemplateBuilder, IMEAIChatTemplateBuilder
{
private const char Newline = '\n';
public static Phi3ChatTemplateBuilder Instance { get; } = new Phi3ChatTemplateBuilder();
public string BuildPrompt(IEnumerable<IMessage> messages, IEnumerable<FunctionContract>? tools = null)
{
var availableRoles = new[] { Role.System, Role.User, Role.Assistant };
if (messages.Any(m => m.GetContent() is null))
{
throw new InvalidOperationException("Please provide a message with content.");
}
if (messages.Any(m => m.GetRole() is null || availableRoles.Contains(m.GetRole()!.Value) == false))
{
throw new InvalidOperationException("Please provide a message with a valid role. The valid roles are System, User, and Assistant.");
}
// construct template based on instruction from
// https://huggingface.co/microsoft/Phi-3-mini-128k-instruct#chat-format
var sb = new StringBuilder();
foreach (var message in messages)
{
var role = message.GetRole()!.Value;
var content = message.GetContent()!;
sb.Append(message switch
{
_ when message.GetRole() == Role.System => $"<|system|>{Newline}{content}<|end|>{Newline}",
_ when message.GetRole() == Role.User => $"<|user|>{Newline}{content}<|end|>{Newline}",
_ when message.GetRole() == Role.Assistant => $"<|assistant|>{Newline}{content}<|end|>{Newline}",
_ => throw new InvalidOperationException("Invalid role.")
});
}View on GitHub (pinned to 7b76e69cf9)
Solutions
- Remove or convert tool/function-role messages to assistant or user messages before building the prompt.
- Flatten tool results into assistant messages with textual content.
- Validate roles in your pipeline before handing history to the template builder.
Example fix
// before var prompt = builder.BuildPrompt(history); // history contains a Role.Tool message // after var prompt = builder.BuildPrompt(history.Where(m => m.GetRole() is Role.System or Role.User or Role.Assistant));
Defensive patterns
Strategy: validation
Validate before calling
var allowed = new[] { Role.System, Role.User, Role.Assistant };
if (messages.Any(m => m.GetRole() is null || !allowed.Contains(m.GetRole()!.Value)))
throw new InvalidOperationException("History contains roles unsupported by Phi-3 (System/User/Assistant only)."); Type guard
bool IsPhi3Role(IMessage m) => m.GetRole() is Role.System or Role.User or Role.Assistant;
Try / catch
try { var prompt = builder.BuildPrompt(messages); } catch (InvalidOperationException ex) when (ex.Message.Contains("valid role")) { messages = messages.Where(IsPhi3Role); prompt = builder.BuildPrompt(messages); } Prevention
- Convert tool/function messages to assistant text before adding them to history.
- Centralize role mapping in one adapter function.
- Pin down message creation so roles can only be the three supported values.
When it happens
Trigger: Calling BuildPrompt with a message whose GetRole() returns null, or whose role is not one of System/User/Assistant — typically tool/function-role messages passed into the template builder.
Common situations: Including AutoGen tool-call or tool-result messages in the history; migrating from another chat library whose roles don't map to Phi-3's three roles; role strings that failed to parse into the Role enum.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid role.
- Unsupported role {message.Role}
- Please provide a message with content.
- Only text content is supported, but got {item.GetType().Name
- Invalid role.
AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11).
Data as JSON: /api/errors/b260e6b6f7912ef3.
Report an issue: GitHub.