{"record":{"id":"b9450e993f22afd1","repo":"microsoft/autogen","slug":"the-first-message-must-be-from-the-user-or-functio","errorCode":null,"errorMessage":"The first message must be from the user or function","messagePattern":"The first message must be from the user or function","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"dotnet/src/AutoGen.Gemini/GeminiChatAgent.cs","lineNumber":173,"sourceCode":"    }\n\n    private GenerateContentRequest BuildChatRequest(IEnumerable<IMessage> messages, GenerateReplyOptions? options)\n    {\n        var geminiMessages = messages.Select(m => m switch\n        {\n            IMessage<Content> contentMessage => contentMessage.Content,\n            _ => throw new NotSupportedException($\"Message type {m.GetType()} is not supported.\")\n        });\n\n        // there are several rules applies to the messages that can be sent to Gemini in a multi-turn chat\n        // - The first message must be from the user or function\n        // - The (user|model) roles must alternate e.g. (user, model, user, model, ...)\n        // - The last message must be from the user or function\n\n        // check if the first message is from the user\n        if (geminiMessages.FirstOrDefault()?.Role != \"user\" && geminiMessages.FirstOrDefault()?.Role != \"function\")\n        {\n            throw new ArgumentException(\"The first message must be from the user or function\", nameof(messages));\n        }\n\n        // check if the last message is from the user\n        if (geminiMessages.LastOrDefault()?.Role != \"user\" && geminiMessages.LastOrDefault()?.Role != \"function\")\n        {\n            throw new ArgumentException(\"The last message must be from the user or function\", nameof(messages));\n        }\n\n        // merge continuous messages with the same role into one message\n        var mergedMessages = geminiMessages.Aggregate(new List<Content>(), (acc, message) =>\n        {\n            if (acc.Count == 0 || acc.Last().Role != message.Role)\n            {\n                acc.Add(message);\n            }\n            else\n            {\n                acc.Last().Parts.AddRange(message.Parts);","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/dotnet/src/AutoGen.Gemini/GeminiChatAgent.cs#L155-L191","documentation":"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'.","triggerScenarios":"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.","commonSituations":"Replaying persisted conversations starting with the assistant, group-chat forwarding where another agent spoke first, or seed messages inserted in the wrong order.","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"],"exampleFix":"// before:\nvar messages = new List<IMessage> { assistantReply, userMsg }; // first is model role -> throws\n// after:\nvar messages = new List<IMessage> { userMsg, assistantReply, userMsg2 }; // starts with user","handlingStrategy":"validation","validationCode":"// Enforce Gemini ordering before the call\nvar first = messages.FirstOrDefault() as IMessage<Content>;\nif (first?.Content.Role is not (\"user\" or \"function\"))\n    messages = new[] { new TextMessage(Role.User, \"continue\") }.Concat(messages);","typeGuard":"static bool StartsAfterUserTurn(IEnumerable<IMessage> msgs) =>\n    (msgs.FirstOrDefault() as IMessage<Content>)?.Content.Role is \"user\" or \"function\";","tryCatchPattern":"try { await geminiAgent.GenerateReplyAsync(messages, options, ct); }\ncatch (ArgumentException e) when (e.Message.Contains(\"first message must be from the user\"))\n{ /* reorder history to put a user/function message first and retry */ }","preventionTips":["Persist conversations starting from the first user turn","Prepend a user message when replaying histories that begin with assistant output"],"tags":["autogen","gemini","chat-history","ordering"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}