microsoft/semantic-kernel · error · ServiceInvalidRequestError

Unsupported role in chat history: {curr_message.role}

Error message

Unsupported role in chat history: {curr_message.role}

What it means

Raised by the Anthropic connector when a chat_history message has an AuthorRole other than SYSTEM, USER, ASSISTANT, or TOOL. The Anthropic Messages API only supports those four roles (with tool results folded into user turns), so any custom or unexpected role cannot be mapped to a valid request message.

Source

Thrown at python/semantic_kernel/connectors/ai/anthropic/services/anthropic_chat_completion.py:247

                    # Under no circumstances should a tool message be the first message in the chat history
                    raise ServiceInvalidRequestError("Tool message found without a preceding message.")
                if prev_message.role == AuthorRole.USER or prev_message.role == AuthorRole.SYSTEM:
                    # A tool message should not be found after a user or system message
                    # Please NOTE that in SK there are the USER role and the TOOL role, but in Anthropic
                    # the tool messages are considered as USER messages. We are checking against the SK roles.
                    raise ServiceInvalidRequestError("Tool message found after a user or system message.")

                formatted_message = MESSAGE_CONVERTERS[curr_message.role](curr_message)
                if prev_message.role == AuthorRole.ASSISTANT:
                    # The first tool message after an assistant message should be a new message
                    formatted_messages.append(formatted_message)
                else:
                    # Append the tool message to the previous tool message.
                    # This indicates that the assistant message requested multiple parallel tool calls.
                    # Anthropic requires that parallel Tool messages are grouped together in a single message.
                    formatted_messages[-1][content_key] += formatted_message[content_key]
            else:
                raise ServiceInvalidRequestError(f"Unsupported role in chat history: {curr_message.role}")

        if system_message_count > 1:
            logger.warning(
                "Anthropic service only supports one system message, but %s system messages were found."
                " Only the first system message will be included in the request.",
                system_message_count,
            )

        return formatted_messages, system_message_content

    # endregion

    def _create_chat_message_content(
        self, response: Message, response_metadata: dict[str, Any]
    ) -> "ChatMessageContent":
        """Create a chat message content object."""
        items: list[CMC_ITEM_TYPES] = []
        items += self._get_tool_calls_from_message(response)

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Filter out or remap non-standard roles before calling the service — convert annotations to USER messages or store them out-of-band.
  2. Ensure every ChatMessageContent.role is one of AuthorRole.SYSTEM, USER, ASSISTANT, or TOOL.
  3. Add a pre-flight filter that drops or warns on unsupported roles (see defense validationCode).

Example fix

// before
history.add_message(ChatMessageContent(role=AuthorRole('annotator'), content="..."))

// after
# keep annotations out of the model-facing history
history.add_user_message("...")
Defensive patterns

Strategy: validation

Validate before calling

from semantic_kernel.contents import AuthorRole

SUPPORTED = {AuthorRole.SYSTEM, AuthorRole.USER, AuthorRole.ASSISTANT, AuthorRole.TOOL}
unsupported = [i for i, m in enumerate(history) if m.role not in SUPPORTED]
assert not unsupported, f"Unsupported roles at indices: {unsupported}"

Type guard

from semantic_kernel.contents import AuthorRole

def is_supported_role(role) -> bool:
    return role in {AuthorRole.SYSTEM, AuthorRole.USER, AuthorRole.ASSISTANT, AuthorRole.TOOL}

Try / catch

from semantic_kernel.exceptions import ServiceInvalidRequestError
try:
    await service.get_chat_message_contents(history=history, settings=settings)
except ServiceInvalidRequestError as e:
    if "Unsupported role" in str(e):
        history = [m for m in history if m.role in SUPPORTED]  # strip annotations

Prevention

When it happens

Trigger: A ChatMessageContent whose role is a custom/named role (e.g. AuthorRole('notes'), 'developer', or any string not in the four supported enums) reaches the formatting loop. Also triggered by accidentally setting role to None or a non-AuthorRole value.

Common situations: Using custom roles for annotations or logging that leak into the history passed to the service; upgrading SK versions where new roles were introduced; programmatically assigning roles from external config without validation.

Related errors


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