microsoft/semantic-kernel · error · ServiceInvalidRequestError

System messages are not supported in Gemma

Error message

System messages are not supported in Gemma

What it means

Google's Gemma models do not support system-role messages in their prompt format. The gemma_template() function explicitly checks every message's role and raises ServiceInvalidRequestError (an HTTP-400-equivalent client error) if any message has AuthorRole.SYSTEM. This is a hard API contract from the model, not a library limitation.

Solutions

  1. Remove or convert the system message to a user message before calling the Gemma service: merge the system instruction into the first user turn.
  2. Filter system messages from ChatHistory right before the call: history.messages = [m for m in history.messages if m.role != AuthorRole.SYSTEM].
  3. Use a different template/model (e.g. ONNXTemplate.PHI3) if you need native system-role support.
  4. Guard at the application layer with a template-aware check so system messages are never sent to Gemma.

Example fix

// before
history.add_system_message("You are a helpful assistant.")
result = gemma_service.get_chat_message_contents(history=history)
// after
system_msg = next((m for m in history.messages if m.role == AuthorRole.SYSTEM), None)
if system_msg:
    history.remove_message(system_msg)
    history.messages.insert(0, ChatMessageContent(role=AuthorRole.USER, content=system_msg.content))
result = gemma_service.get_chat_message_contents(history=history)
Defensive patterns

Strategy: validation

Validate before calling

from semantic_kernel.contents import AuthorRole

def strip_system_messages_for_gemma(history):
    """Remove system messages before sending to Gemma — merge into first user turn."""
    system_msgs = [m for m in history.messages if m.role == AuthorRole.SYSTEM]
    if system_msgs:
        history.messages = [m for m in history.messages if m.role != AuthorRole.SYSTEM]
        merged = ' '.join(m.content for m in system_msgs)
        if history.messages and history.messages[0].role == AuthorRole.USER:
            history.messages[0].content = merged + '\n' + history.messages[0].content
    return history

Type guard

def is_gemma_compatible(history) -> bool:
    return all(m.role != AuthorRole.SYSTEM for m in history.messages)

Try / catch

from semantic_kernel.exceptions import ServiceInvalidRequestError

try:
    result = gemma_service.get_chat_message_contents(history=history)
except ServiceInvalidRequestError as e:
    if 'System messages' in str(e):
        history = strip_system_messages_for_gemma(history)
        result = gemma_service.get_chat_message_contents(history=history)

Prevention

When it happens

Trigger: Calling an ONNX Gemma chat completion with a ChatHistory that contains at least one message where role == AuthorRole.SYSTEM — typically from adding a system prompt via history.add_system_message() or a kernel function that auto-injects one.

Common situations: Using the same ChatHistory builder across models (a system prompt that works for GPT/Phi fails for Gemma); templated pipelines that always prepend a system instruction; copying examples designed for OpenAI models into a Gemma workflow.

Related errors


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

Appendix: source

Thrown at python/semantic_kernel/connectors/ai/onnx/utils.py:167

    return phi4mm_input


def gemma_template(history: ChatHistory) -> str:
    """Generates a formatted string for the Gemma model based on the provided chat history.

    Args:
        history (ChatHistory): An object containing the chat history with messages.

    Returns:
        str: A formatted string representing the chat history for the Gemma model.

    Raises:
        ServiceInvalidRequestError: If a system message is encountered in the chat history.
    """
    gemma_input = "<bos>"
    for message in history.messages:
        if message.role == AuthorRole.SYSTEM:
            raise ServiceInvalidRequestError("System messages are not supported in Gemma")
        if message.role == AuthorRole.USER:
            gemma_input += f"<start_of_turn>user\n{message.content}<end_of_turn>\n"
        if message.role == AuthorRole.ASSISTANT:
            gemma_input += f"<start_of_turn>model\n{message.content}<end_of_turn>\n"
    gemma_input += "<start_of_turn>model\n"
    return gemma_input


def llama_template(history: ChatHistory) -> str:
    """Generates a formatted string from a given chat history for use with the LLaMA model.

    Args:
        history (ChatHistory): An object containing the chat history, which includes a list of messages.

    Returns:
        str: A formatted string where each message is wrapped with specific header and end tags,
             and the final string ends with an assistant header tag.
    """

View on GitHub (pinned to c028a0c7dc)