{"record":{"id":"3e5ea93b18d92bc0","repo":"microsoft/semantic-kernel","slug":"invalid-message-role-message-role-value-allow","errorCode":null,"errorMessage":"Invalid message role `{message.role.value}`. Allowed roles are {allowed_message_roles}.","messagePattern":"Invalid message role `(.+?)`\\. Allowed roles are (.+?)\\.","errorType":"exception","errorClass":"AgentExecutionException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/agents/open_ai/assistant_content_generation.py","lineNumber":73,"sourceCode":") -> \"Message\":\n    \"\"\"Class method to add a chat message, callable from class or instance.\n\n    Args:\n        client: The client to use for creating the message.\n        thread_id: The thread id.\n        message: The chat message.\n        allowed_message_roles: The allowed message roles.\n            Defaults to [AuthorRole.USER, AuthorRole.ASSISTANT] if None.\n            Providing an empty list will disallow all message roles.\n\n    Returns:\n        Message: The message.\n    \"\"\"\n    # Set the default allowed message roles if not provided\n    if allowed_message_roles is None:\n        allowed_message_roles = [AuthorRole.USER, AuthorRole.ASSISTANT]\n    if message.role.value not in allowed_message_roles and message.role != AuthorRole.TOOL:\n        raise AgentExecutionException(\n            f\"Invalid message role `{message.role.value}`. Allowed roles are {allowed_message_roles}.\"\n        )\n\n    message_contents: list[dict[str, Any]] = get_message_contents(message=message)\n\n    return await client.beta.threads.messages.create(\n        thread_id=thread_id,\n        role=\"assistant\" if message.role == AuthorRole.TOOL else message.role.value,  # type: ignore\n        content=message_contents,  # type: ignore\n    )\n\n\n@experimental\ndef get_message_contents(message: \"ChatMessageContent\") -> list[dict[str, Any]]:\n    \"\"\"Get the message contents.\n\n    Args:\n        message: The message.","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/agents/open_ai/assistant_content_generation.py#L55-L91","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nhistory.add(MessageRole.SYSTEM, \"You are a helpful agent\")\nawait assistant.invoke(thread_id=tid, messages=history)  # SYSTEM -> Invalid message role\n\n// after\n# put system guidance in the assistant definition, only user/assistant in the thread\nhistory.add(MessageRole.USER, \"Summarize the report\")\nawait assistant.invoke(thread_id=tid, messages=history)","handlingStrategy":"validation","validationCode":"from semantic_kernel.contents import AuthorRole\n\nALLOWED = {AuthorRole.USER, AuthorRole.ASSISTANT, AuthorRole.TOOL}\n\ndef safe_for_thread(msg) -> bool:\n    return msg.role in ALLOWED","typeGuard":"from semantic_kernel.contents import AuthorRole\n\ndef is_thread_safe_role(msg) -> bool:\n    return msg.role in (AuthorRole.USER, AuthorRole.ASSISTANT, AuthorRole.TOOL)","tryCatchPattern":null,"preventionTips":["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."],"tags":["openai","assistant","message-role","validation"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}