dotnet/machinelearning · error · InvalidOperationException
Invalid role.
Error message
Invalid role.
What it means
Mistral_7B_0_3ChatTemplateBuilder.BuildPrompt formats each message in a ChatHistory into Mistral's [INST]...[/INST] template. Only ToolCall/ToolResult/aggregate messages and TextMessage with Role.User or Role.Assistant are supported; any other role (e.g. System passed as a TextMessage after the first message, or a custom role) falls into the default arm and throws InvalidOperationException.
Source
Thrown at src/Microsoft.ML.GenAI.Mistral/Mistral_7B_0_3ChatTemplateBuilder.cs:60
var sb = new StringBuilder();
foreach (var message in firstSequence)
{
// skip system
if (message.GetRole() == Role.System)
{
continue;
}
var content = message.GetContent()!;
sb.Append(message switch
{
ToolCallMessage toolCallMessage => BuildFromToolCallMessage(toolCallMessage),
ToolCallResultMessage toolCallResultMessage => BuildFromToolCallResultMessage(toolCallResultMessage),
ToolCallAggregateMessage toolCallAggregateMessage => BuildFromAggregrateToolCallMessage(toolCallAggregateMessage),
TextMessage when message.GetRole() == Role.User => $"[INST]{content.Trim()}[/INST]",
TextMessage when message.GetRole() == Role.Assistant => $"{content.Trim()}</s>",
_ => throw new InvalidOperationException("Invalid role.")
});
}
// insert [AVAILABLE TOOLS] section if tools are provided
if (tools?.Any() == true)
{
var schemas = tools.Select(t => new
{
type = "function",
function = new
{
name = t.Name,
description = t.Description,
parameters = BuildJsonSchemaFromFunctionContract(t)
}
});
var schemaPrompt = JsonSerializer.Serialize(schemas);
View on GitHub (pinned to 7b76e69cf9)
Solutions
- Ensure all messages are TextMessage with Role.User or Role.Assistant (or tool-call message types)
- Fold system instructions into the first user message instead of a separate System TextMessage
- Add a pattern arm for the extra role you need, e.g. TextMessage when message.GetRole() == Role.System => system-style formatting
- Catch InvalidOperationException around BuildPrompt and log message.GetRole() to identify the offending message
Example fix
// before new TextMessage(Role.System, "You are helpful.") // after new TextMessage(Role.User, "You are helpful.\n\n" + userContent)
Defensive patterns
Strategy: validation
Validate before calling
bool allRolesValid = messages.OfType<TextMessage>().All(m => m.GetRole() == Role.User || m.GetRole() == Role.Assistant);
if (!allRolesValid) throw new ArgumentException("Mistral template supports only User/Assistant text messages"); Type guard
static bool IsSupportedMessage(Message m) =>
m is ToolCallMessage or ToolCallResultMessage or ToolCallAggregateMessage ||
(m is TextMessage t && (t.GetRole() == Role.User || t.GetRole() == Role.Assistant)); Try / catch
try { prompt = builder.BuildPrompt(messages, systemMessage, tools); }
catch (InvalidOperationException ex) { log.Error("Unsupported role in chat history", ex); throw; } Prevention
- Map roles to User/Assistant before templating
- Fold system prompts into the first user message
- Unit-test prompt building with every role your app emits
When it happens
Trigger: Calling BuildPrompt(IEnumerable<Message> chatHistory, ...) with a TextMessage whose GetRole() is neither User nor Assistant — most commonly a System TextMessage appearing after position 0, or a message whose role string was parsed as something unexpected.
Common situations: Porting code from another chat template (e.g. Llama) that accepts a System role anywhere in the history; hand-built ChatHistory with a system-style TextMessage; a new Role enum value added upstream but not handled by the Mistral template.
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
- Please provide a message with content.
- Please provide a message with a valid role. The valid roles
- Invalid role.
- Only text content is supported, but got {item.GetType().Name
- Unsupported role {message.Role}
AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11).
Data as JSON: /api/errors/092a4ad5baa88fc1.
Report an issue: GitHub.