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.

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)

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.