{"record":{"id":"3bf9e26add901737","repo":"microsoft/semantic-kernel","slug":"chat-history-can-t-contain-only-system-messages","errorCode":null,"errorMessage":"Chat history can't contain only system messages.","messagePattern":"Chat history can't contain only system messages\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Connectors/Connectors.Google/Core/Gemini/Clients/GeminiChatCompletionClient.cs","lineNumber":768,"sourceCode":"    private static bool IsRequestableTool(IEnumerable<GeminiTool.FunctionDeclaration> functions, GeminiFunctionToolCall ftc)\n        => functions.Any(geminiFunction =>\n            string.Equals(geminiFunction.Name, ftc.FullyQualifiedName, StringComparison.OrdinalIgnoreCase));\n\n    private static bool CheckAutoInvokeCondition(Kernel? kernel, GeminiPromptExecutionSettings geminiExecutionSettings)\n    {\n        bool autoInvoke = kernel is not null\n                          && geminiExecutionSettings.ToolCallBehavior?.MaximumAutoInvokeAttempts > 0\n                          && s_inflightAutoInvokes.Value < MaxInflightAutoInvokes;\n        ValidateAutoInvoke(autoInvoke, geminiExecutionSettings.CandidateCount ?? 1);\n        return autoInvoke;\n    }\n\n    private static void ValidateChatHistory(ChatHistory chatHistory)\n    {\n        Verify.NotNullOrEmpty(chatHistory);\n        if (chatHistory.All(message => message.Role == AuthorRole.System))\n        {\n            throw new InvalidOperationException(\"Chat history can't contain only system messages.\");\n        }\n    }\n\n    private async IAsyncEnumerable<GeminiChatMessageContent> ProcessChatResponseStreamAsync(\n        Stream responseStream,\n        [EnumeratorCancellation] CancellationToken ct)\n    {\n        await foreach (var response in this.ParseResponseStreamAsync(responseStream, ct: ct).ConfigureAwait(false))\n        {\n            foreach (var messageContent in this.ProcessChatResponse(response))\n            {\n                yield return messageContent;\n            }\n        }\n    }\n\n    private async IAsyncEnumerable<GeminiResponse> ParseResponseStreamAsync(\n        Stream responseStream,","sourceCodeStart":750,"sourceCodeEnd":786,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/dotnet/src/Connectors/Connectors.Google/Core/Gemini/Clients/GeminiChatCompletionClient.cs#L750-L786","documentation":"Thrown by GeminiChatCompletionClient.ValidateChatHistory when every message in the ChatHistory has AuthorRole.System. Gemini requires at least one non-system message (a user or assistant turn) to generate a response. An all-system history has no actual conversation content for the model to respond to.","triggerScenarios":"Calling GetChatMessageContentsAsync (or the streaming variant) with a ChatHistory where chatHistory.All(m => m.Role == AuthorRole.System) returns true. This means zero non-system messages exist. An empty history is caught earlier by Verify.NotNullOrEmpty.","commonSituations":"Building a chat history programmatically and only adding system instructions. Copying a history from another connector that stores everything as system messages. Forgetting to append the actual user query after setting up the system prompt.","solutions":["Add at least one user or assistant message to the chat history before calling the Gemini client.","Move system instructions to GeminiPromptExecutionSettings.SystemInstruction instead of using AuthorRole.System messages.","Validate the history before the call: if (history.All(m => m.Role == AuthorRole.System)) throw new InvalidOperationException(\"Add a user message.\");"],"exampleFix":"// before — only system messages\nhistory.AddSystemMessage(\"You are a translator.\");\nawait client.GetChatMessageContentsAsync(history);\n\n// after — add a user message\nhistory.AddSystemMessage(\"You are a translator.\");\nhistory.AddUserMessage(\"Translate 'hello' to French.\");\nawait client.GetChatMessageContentsAsync(history);","handlingStrategy":"validation","validationCode":"if (chatHistory.All(m => m.Role == AuthorRole.System))\n{\n    throw new InvalidOperationException(\n        \"Chat history must contain at least one non-system message for Gemini.\");\n}\n// or auto-fix by adding a placeholder user message\nif (chatHistory.Count > 0 && chatHistory.All(m => m.Role == AuthorRole.System))\n{\n    chatHistory.AddUserMessage(\"(continue)\");\n}","typeGuard":"static bool HasNonSystemMessage(ChatHistory history) =>\n    history.Any(m => m.Role != AuthorRole.System);","tryCatchPattern":"try { var result = await client.GetChatMessageContentsAsync(history); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"only system messages\"))\n{\n    logger.LogWarning(\"Chat history had only system messages; adding user prompt.\");\n    history.AddUserMessage(userInput);\n    result = await client.GetChatMessageContentsAsync(history);\n}","preventionTips":["Always include at least one user message in the chat history before calling Gemini.","Use GeminiPromptExecutionSettings.SystemInstruction for system prompts instead of System-role messages.","Validate chat history structure before sending to any LLM connector."],"tags":["google","gemini","chat-history","validation","system-message"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}