microsoft/semantic-kernel · error · InvalidOperationException

Bedrock agents must be invoked with a user message

Error message

Bedrock agents must be invoked with a user message

What it means

Thrown by BedrockAgent.ExtractUserMessage when the message's role is not AuthorRole.User. Bedrock agents expect the final/invoking message to be a user message; assistant or system messages in that slot are rejected. This validates the last message before sending it as the agent input.

Source

Thrown at dotnet/src/Agents/Bedrock/BedrockAgent.cs:550

        string agentAlias = WorkingDraftAgentAlias;
        bool enableTrace = false;
        if (options is BedrockAgentInvokeOptions bedrockOption)
        {
            agentAlias = bedrockOption.AgentAliasId ?? WorkingDraftAgentAlias;
            enableTrace = bedrockOption.EnableTrace;
        }

        var invokeRequest = createRequest();
        invokeRequest.AgentAliasId = agentAlias;
        invokeRequest.EnableTrace = enableTrace;
        return invokeRequest;
    }

    private string ExtractUserMessage(ChatMessageContent chatMessageContent)
    {
        if (!chatMessageContent.Role.Equals(AuthorRole.User))
        {
            throw new InvalidOperationException("Bedrock agents must be invoked with a user message");
        }

        return chatMessageContent.Content ?? "";
    }

    private SessionState ExtractSessionState(ICollection<ChatMessageContent> messages)
    {
        // If there is more than one message provided, add all but the last message to the session state
        SessionState sessionState = new();
        if (messages.Count > 1)
        {
            List<Amazon.BedrockAgentRuntime.Model.Message> messageHistory = [];
            for (int i = 0; i < messages.Count - 1; i++)
            {
                var currentMessage = messages.ElementAt(i);
                messageHistory.Add(this.ToBedrockMessage(currentMessage));
            }

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Ensure the last message in the collection has Role == AuthorRole.User.
  2. If the latest turn is an assistant reply, append a user turn (even a continuation prompt) before invoking.

Example fix

// before
var messages = new List<ChatMessageContent>
{
    new(AuthorRole.User, "hi"),
    new(AuthorRole.Assistant, "hello!"), // last is assistant -> throws 177
};
await agent.InvokeAsync(messages);

// after
messages.Add(new(AuthorRole.User, "tell me more"));
await agent.InvokeAsync(messages);
Defensive patterns

Strategy: type-guard

Validate before calling

var last = messages.Last();
if (!last.Role.Equals(AuthorRole.User))
    throw new InvalidOperationException("The final message must be a user message for Bedrock agents.");

Type guard

static bool LastIsUser(ICollection<ChatMessageContent> m) =>
    m.Count > 0 && m.Last().Role.Equals(AuthorRole.User);

Try / catch

try { await agent.InvokeAsync(messages); }
catch (InvalidOperationException ex) when (ex.Message.Contains("user message"))
{ /* append a user message as the last entry and retry */ }

Prevention

When it happens

Trigger: The message passed as the primary input to ExtractUserMessage has Role equal to Assistant, System, Tool, or anything other than User.

Common situations: Caller appended an assistant follow-up as the last message by mistake; message history ordering put a non-user message last; tool/result message placed in the user slot.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/4cd278555d47d743. Report an issue: GitHub.