microsoft/semantic-kernel · error · AgentExecutionException
Invalid message role `{message.role.value}`. Allowed roles a
Error message
Invalid message role `{message.role.value}`. Allowed roles are {allowed_message_roles}. What it means
Before adding a message to an OpenAI Assistant thread, the helper verifies the message role is permitted. allowed_message_roles defaults to [USER, ASSISTANT] when None, and TOOL is always implicitly allowed. Any other role (e.g. SYSTEM, a custom role) raises AgentExecutionException because the OpenAI threads API only accepts user/assistant/tool messages in this flow.
Source
Thrown at python/semantic_kernel/agents/open_ai/assistant_content_generation.py:73
) -> "Message":
"""Class method to add a chat message, callable from class or instance.
Args:
client: The client to use for creating the message.
thread_id: The thread id.
message: The chat message.
allowed_message_roles: The allowed message roles.
Defaults to [AuthorRole.USER, AuthorRole.ASSISTANT] if None.
Providing an empty list will disallow all message roles.
Returns:
Message: The message.
"""
# Set the default allowed message roles if not provided
if allowed_message_roles is None:
allowed_message_roles = [AuthorRole.USER, AuthorRole.ASSISTANT]
if message.role.value not in allowed_message_roles and message.role != AuthorRole.TOOL:
raise AgentExecutionException(
f"Invalid message role `{message.role.value}`. Allowed roles are {allowed_message_roles}."
)
message_contents: list[dict[str, Any]] = get_message_contents(message=message)
return await client.beta.threads.messages.create(
thread_id=thread_id,
role="assistant" if message.role == AuthorRole.TOOL else message.role.value, # type: ignore
content=message_contents, # type: ignore
)
@experimental
def get_message_contents(message: "ChatMessageContent") -> list[dict[str, Any]]:
"""Get the message contents.
Args:
message: The message.View on GitHub (pinned to c028a0c7dc)
Solutions
- Filter out or convert non-conforming messages before invoking: keep only USER and ASSISTANT (and TOOL) roles.
- If you intentionally restrict roles, make sure the messages you submit match allowed_message_roles (or rely on the default).
- Move SYSTEM instructions into the assistant's instructions/model config rather than the thread messages.
Example fix
// before history.add(MessageRole.SYSTEM, "You are a helpful agent") await assistant.invoke(thread_id=tid, messages=history) # SYSTEM -> Invalid message role // after # put system guidance in the assistant definition, only user/assistant in the thread history.add(MessageRole.USER, "Summarize the report") await assistant.invoke(thread_id=tid, messages=history)
Defensive patterns
Strategy: validation
Validate before calling
from semantic_kernel.contents import AuthorRole
ALLOWED = {AuthorRole.USER, AuthorRole.ASSISTANT, AuthorRole.TOOL}
def safe_for_thread(msg) -> bool:
return msg.role in ALLOWED Type guard
from semantic_kernel.contents import AuthorRole
def is_thread_safe_role(msg) -> bool:
return msg.role in (AuthorRole.USER, AuthorRole.ASSISTANT, AuthorRole.TOOL) Prevention
- Pre-filter chat history to USER/ASSISTANT roles before passing to assistant threads.
- Put system guidance in the assistant instructions, not thread messages.
- Do not pass allowed_message_roles unless you intentionally need to restrict.
When it happens
Trigger: Calling get_chat_message_content / the message-create helper with a ChatMessageContent whose role is SYSTEM (or any non-USER/ASSISTANT/TOOL role), or with a role excluded by an explicitly passed allowed_message_roles list.
Common situations: Forwarding a system prompt ChatMessageContent into the assistant thread; reusing a chat-history that contains SYSTEM entries; passing allowed_message_roles=[AuthorRole.USER] and then submitting an assistant-authored message; empty allowed_message_roles=[] which disallows everything except TOOL.
Related errors
- Invalid message role `{message.role.value}`. Allowed roles a
- FunctionChoiceBehavior with type '{function_choice_behavior.
- FunctionChoiceBehavior.Auto(auto_invoke=False) is not suppor
- FunctionChoiceBehavior filters must not be empty. Provide at
- Unknown filter key(s): {sorted(unknown_keys)}. Valid filter
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/3e5ea93b18d92bc0.
Report an issue: GitHub.