dotnet/machinelearning · error · InvalidOperationException
Invalid role.
Error message
Invalid role.
What it means
Exhaustive switch fallback inside BuildPrompt's prompt-assembly loop. Given the preceding validation, this is an internal-invariant guard: if execution reaches it, a message role passed all earlier checks but matched none of the System/User/Assistant branches.
Source
Thrown at src/Microsoft.ML.GenAI.LLaMA/Llama3_1ChatTemplateBuilder.cs:47
{
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://github.com/meta-llama/llama3/blob/11817d47e1ba7a4959b025eb1ca308572e0e3963/llama/generation.py#L280
var sb = new StringBuilder();
sb.Append("<|begin_of_text|>");
foreach (var message in messages)
{
var role = message.GetRole()!.Value;
var content = message.GetContent()!;
sb.Append(message switch
{
_ when message.GetRole() == Role.System => $"<|start_header_id|>system<|end_header_id|>{Newline}{content.Trim()}<|eot_id|>{Newline}",
_ when message.GetRole() == Role.User => $"<|start_header_id|>user<|end_header_id|>{Newline}{content.Trim()}<|eot_id|>{Newline}",
_ when message.GetRole() == Role.Assistant => $"<|start_header_id|>assistant<|end_header_id|>{Newline}{content.Trim()}<|eot_id|>{Newline}",
_ => throw new InvalidOperationException("Invalid role.")
});
}
sb.Append($"<|start_header_id|>assistant<|end_header_id|>{Newline}");
var input = sb.ToString();
return input;
}
public string BuildPrompt(ChatHistory chatHistory)
{
// build prompt from chat history
var sb = new StringBuilder();
sb.Append("<|begin_of_text|>");
foreach (var message in chatHistory)
{
foreach (var item in message.Items)View on GitHub (pinned to 7b76e69cf9)
Solutions
- Use only the canonical Role.System, Role.User, Role.Assistant values (don't define look-alike roles).
- Verify the same messages collection is validated and rendered.
- Normalize roles to the canonical three before calling BuildPrompt.
- If you believe roles are valid, inspect message.GetRole() values to find the unexpected one.
Example fix
// before
var role = new Role("assistant"); // look-alike, not the canonical member
// after
var role = Role.Assistant; // canonical value Defensive patterns
Strategy: validation
Validate before calling
var canonical = new HashSet<Role> { Role.System, Role.User, Role.Assistant };
if (messages.Any(m => !canonical.Contains(m.GetRole()!.Value)))
throw new InvalidOperationException("Non-canonical role detected before BuildPrompt."); Type guard
static bool IsCanonicalRole(IMessage m) =>
ReferenceEquals(m.GetRole(), Role.System) ||
ReferenceEquals(m.GetRole(), Role.User) ||
ReferenceEquals(m.GetRole(), Role.Assistant); Try / catch
try { prompt = builder.BuildPrompt(messages); }
catch (InvalidOperationException ex) when (ex.Message == "Invalid role.")
{ log.Error("Role slipped past validation; check for custom Role instances"); throw; } Prevention
- Use only the canonical Role static members; avoid look-alike instances.
- Freeze the message list (ToList) before validation and rendering.
- Treat this throw as a bug signal and log the offending role value.
When it happens
Trigger: A message whose GetRole() returned a value that slipped past the earlier role validation (e.g. a custom Role value that compares unequal in the switch but was accepted earlier, or validation executed over a different message collection than the one rendered).
Common situations: Custom Role static members added by consumers that don't equal the canonical three; collections mutated between validation and rendering; role comparisons relying on reference equality with differing Role instances.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Please provide a message with a valid role. The valid roles
- Please provide a message with content.
- Unsupported role {message.Role}
- {0} {1}
- Did not find access modifier (Parameter 'methodInfo')
AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11).
Data as JSON: /api/errors/7a68c13003620adc.
Report an issue: GitHub.