microsoft/autogen · error · InvalidOperationException
Invalid Role
Error message
Invalid Role
What it means
Thrown by ProcessTextMessage when a TextMessage has From == null and a Role that is neither User nor Assistant (System is handled earlier, so this typically means Role.Tool or an unexpected role). The connector cannot decide whether to emit a ChatRequestUserMessage or ChatRequestAssistantMessage for an anonymous sender with an ambiguous role.
Source
Thrown at dotnet/src/AutoGen.OpenAI.V1/Middleware/OpenAIChatRequestMessageConnector.cs:286
private IEnumerable<ChatRequestMessage> ProcessTextMessage(IAgent agent, TextMessage message)
{
if (message.Role == Role.System)
{
return [new ChatRequestSystemMessage(message.Content) { Name = message.From }];
}
if (agent.Name == message.From)
{
return [new ChatRequestAssistantMessage(message.Content) { Name = agent.Name }];
}
else
{
return message.From switch
{
null when message.Role == Role.User => [new ChatRequestUserMessage(message.Content)],
null when message.Role == Role.Assistant => [new ChatRequestAssistantMessage(message.Content)],
null => throw new InvalidOperationException("Invalid Role"),
_ => [new ChatRequestUserMessage(message.Content) { Name = message.From }]
};
}
}
private IEnumerable<ChatRequestMessage> ProcessImageMessage(IAgent agent, ImageMessage message)
{
if (agent.Name == message.From)
{
// image message from assistant is not supported
throw new ArgumentException("ImageMessage is not supported when message.From is the same with agent");
}
var imageContentItem = this.CreateChatMessageImageContentItemFromImageMessage(message);
return [new ChatRequestUserMessage([imageContentItem]) { Name = message.From }];
}
private IEnumerable<ChatRequestMessage> ProcessMultiModalMessage(IAgent agent, MultiModalMessage message)View on GitHub (pinned to 027ecf0a37)
Solutions
- Set From on the TextMessage (any non-null value routes to ChatRequestUserMessage)
- Use Role.User or Role.Assistant for anonymous text messages
- Represent tool outputs as ToolCallResultMessage rather than TextMessage(Role.Tool, ...)
Example fix
// before var msg = new TextMessage(Role.Tool, "tool output"); // From == null -> throws // after var msg = new ToolCallResultMessage(toolCallId, "tool output", functionName, from: "Tool");
Defensive patterns
Strategy: validation
Validate before calling
if (textMessage.From is null && textMessage.Role is not (Role.User or Role.Assistant or Role.System)) { /* set From or fix the role */ } Type guard
static bool HasValidAnonymousRole(TextMessage m) => m.From is not null || m.Role is Role.User or Role.Assistant or Role.System;
Try / catch
catch (InvalidOperationException ex) when (ex.Message == "Invalid Role") { /* normalize role/from and retry once */ } Prevention
- Always set From on messages built programmatically
- Use ToolCallResultMessage for tool outputs, never TextMessage(Role.Tool)
- Validate message shape in a helper before sending
When it happens
Trigger: Constructing new TextMessage(Role.Tool, ...) (or any non-User/Assistant/System role) without setting From, then sending it to an agent using this connector.
Common situations: Tool-result messages mistakenly created as TextMessage with Role.Tool instead of ToolCallResultMessage; role enums extended with custom values; messages built by generic code that leaves From unset.
Related errors
- Please set AZURE_OPENAI_API_KEY environment variable.
- Please set AZURE_OPENAI_ENDPOINT environment variable.
- Please set environment variable AZURE_OPENAI_API_KEY
- All agents must have a name.
- All agents must have a unique name.
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/61e11a0343791b3b.
Report an issue: GitHub.