microsoft/autogen · error · ArgumentException
The first message must be from the user or function
Error message
The first message must be from the user or function
What it means
Thrown by GeminiChatAgent.BuildChatRequest because the Gemini multi-turn chat API requires the conversation to start with a 'user' (or 'function') role message. If the first converted Content has any other role (typically 'model'/assistant, or a system message first), ArgumentException is thrown with paramName 'messages'.
Source
Thrown at dotnet/src/AutoGen.Gemini/GeminiChatAgent.cs:173
}
private GenerateContentRequest BuildChatRequest(IEnumerable<IMessage> messages, GenerateReplyOptions? options)
{
var geminiMessages = messages.Select(m => m switch
{
IMessage<Content> contentMessage => contentMessage.Content,
_ => throw new NotSupportedException($"Message type {m.GetType()} is not supported.")
});
// there are several rules applies to the messages that can be sent to Gemini in a multi-turn chat
// - The first message must be from the user or function
// - The (user|model) roles must alternate e.g. (user, model, user, model, ...)
// - The last message must be from the user or function
// check if the first message is from the user
if (geminiMessages.FirstOrDefault()?.Role != "user" && geminiMessages.FirstOrDefault()?.Role != "function")
{
throw new ArgumentException("The first message must be from the user or function", nameof(messages));
}
// check if the last message is from the user
if (geminiMessages.LastOrDefault()?.Role != "user" && geminiMessages.LastOrDefault()?.Role != "function")
{
throw new ArgumentException("The last message must be from the user or function", nameof(messages));
}
// merge continuous messages with the same role into one message
var mergedMessages = geminiMessages.Aggregate(new List<Content>(), (acc, message) =>
{
if (acc.Count == 0 || acc.Last().Role != message.Role)
{
acc.Add(message);
}
else
{
acc.Last().Parts.AddRange(message.Parts);View on GitHub (pinned to 027ecf0a37)
Solutions
- Reorder messages so the first message has role "user" (prepend a user message like "continue" if needed)
- Drop or convert leading assistant/system messages before sending (system content can often be merged into the first user turn)
- Use GeminiMessageConnector plus consistent chat history construction from the library's chat abstractions, which maintain the ordering
Example fix
// before:
var messages = new List<IMessage> { assistantReply, userMsg }; // first is model role -> throws
// after:
var messages = new List<IMessage> { userMsg, assistantReply, userMsg2 }; // starts with user Defensive patterns
Strategy: validation
Validate before calling
// Enforce Gemini ordering before the call
var first = messages.FirstOrDefault() as IMessage<Content>;
if (first?.Content.Role is not ("user" or "function"))
messages = new[] { new TextMessage(Role.User, "continue") }.Concat(messages); Type guard
static bool StartsAfterUserTurn(IEnumerable<IMessage> msgs) =>
(msgs.FirstOrDefault() as IMessage<Content>)?.Content.Role is "user" or "function"; Try / catch
try { await geminiAgent.GenerateReplyAsync(messages, options, ct); }
catch (ArgumentException e) when (e.Message.Contains("first message must be from the user"))
{ /* reorder history to put a user/function message first and retry */ } Prevention
- Persist conversations starting from the first user turn
- Prepend a user message when replaying histories that begin with assistant output
When it happens
Trigger: Passing a chat history whose first message is from the assistant (e.g. you saved a prior Gemini reply first), a system-role Content, or a function-result-after-model ordering that leaves a model message at index 0.
Common situations: Replaying persisted conversations starting with the assistant, group-chat forwarding where another agent spoke first, or seed messages inserted in the wrong order.
Related errors
- The last message must be from the user or function
- Message type {m.GetType()} is not supported.
- Failed to generate content. Status code: {response.StatusCod
- Unsupported message type: {reply.GetType()}
- The response should contain either text or tool calls.
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/b9450e993f22afd1.
Report an issue: GitHub.