microsoft/autogen · error · InvalidOperationException

Invalid Role

Error message

Invalid Role

What it means

ProcessTextMessage maps a TextMessage with From == null to a UserChatMessage or AssistantChatMessage based on Role. Only Role.User and Role.Assistant are handled; any other role (typically Role.System, or a custom/undefined role) with a null sender throws 'Invalid Role'.

Source

Thrown at dotnet/src/AutoGen.OpenAI/Middleware/OpenAIChatRequestMessageConnector.cs:259

    private IEnumerable<ChatMessage> ProcessTextMessage(IAgent agent, TextMessage message)
    {
        if (message.Role == Role.System)
        {
            return [new SystemChatMessage(message.Content) { ParticipantName = message.From }];
        }

        if (agent.Name == message.From)
        {
            return [new AssistantChatMessage(message.Content) { ParticipantName = agent.Name }];
        }
        else
        {
            return message.From switch
            {
                null when message.Role == Role.User => [new UserChatMessage(message.Content)],
                null when message.Role == Role.Assistant => [new AssistantChatMessage(message.Content)],
                null => throw new InvalidOperationException("Invalid Role"),
                _ => [new UserChatMessage(message.Content) { ParticipantName = message.From }]
            };
        }
    }

    private IEnumerable<ChatMessage> 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 UserChatMessage([imageContentItem]) { ParticipantName = message.From }];
    }

    private IEnumerable<ChatMessage> ProcessMultiModalMessage(IAgent agent, MultiModalMessage message)

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Set From on the message (any non-null value) so it maps to UserChatMessage with ParticipantName.
  2. Use Role.User or Role.Assistant for sender-less messages instead of Role.System.
  3. Deliver system prompts via the agent's system instructions / SystemChatMessage at construction, not as a runtime TextMessage.

Example fix

// before
var msg = new TextMessage(Role.System, "You are a helpful pirate"); // From is null

// after
var msg = new TextMessage(Role.System, "You are a helpful pirate", from: "system");
Defensive patterns

Strategy: validation

Validate before calling

static TextMessage CreateSafeText(Role role, string content, string? from = null)
{
    if (from is null && role is not (Role.User or Role.Assistant))
        throw new ArgumentException($"TextMessage with role {role} must set From.");
    return new TextMessage(role, content, from);
}

Try / catch

catch (InvalidOperationException ex) when (ex.Message == "Invalid Role")
{
    // re-issue with explicit sender
    return new TextMessage(Role.User, content, from: "system");
}

Prevention

When it happens

Trigger: Sending new TextMessage(Role.System, ...) (or Role.Custom) without setting the From field to this agent's conversation partner.

Common situations: Developers moving a system prompt from agent construction into the message history; porting code from the legacy Message type where Role.System with null From was accepted; typos in role selection.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/9cffa32bef1712e9. Report an issue: GitHub.